Ikke's blog » django http://eikke.com 'cause this is what I do Sun, 13 Feb 2011 14:58:55 +0000 en-US hourly 1 http://wordpress.org/?v=3.4.1 django-validation now includes inheritance support http://eikke.com/django-validation-now-includes-inheritance-support/ http://eikke.com/django-validation-now-includes-inheritance-support/#comments Fri, 18 Jan 2008 03:33:39 +0000 Nicolas http://eikke.com/django-validation-now-includes-inheritance-support/ I’m happy to announce django-validation got field type inheritance support since a couple of minutes. This means your form fields will be validated starting from the most base field type (django.newforms.Field) up to the actual field type (no multiple-inheritance supported though).

In the example I wrote yesterday, when using a TestField field, this field will be validated as a django.newforms.Field (a “required” check will be done), then as a django.newforms.CharField (“min_length” and “max_length” checks), and finally as a TestField. A normal CharField would be validated as a Field first, then as a CharField, etc.

The returned errors will be a list of all errors found, starting with the most basic one (the ones found by the most general class, Field).

Next to this, all generated Javascript code should be namespaced now (based on Python module and class names), although there might be some bad things left, I’m no Javascript guru. The generated code might be somewhat messy.

Current Python code is most certainly ugly and will need more rewrites. Next to this, other field types should be added, and some tests would be nice too.

I made a snapshot of yesterday’s sample (with some changes, the ClientValidator API slightly changed), you can try it here.

]]>
http://eikke.com/django-validation-now-includes-inheritance-support/feed/ 0
django-validation: an introduction http://eikke.com/django-validation-an-introduction/ http://eikke.com/django-validation-an-introduction/#comments Tue, 15 Jan 2008 23:59:58 +0000 Nicolas http://eikke.com/django-validation-an-introduction/ Some time ago I wrote this generic AJAX Django form validation code. Some people didn’t like this, as AJAX should not be used to perform form validation, which is sometimes true, sometimes not, as I pointed out before.

So I’ve been thinking since some time to create a Django templatetag which allows one to generate client-side Javascript form validation code without writing any code himself (unless using custom widgets). Today I got into it.

The resulting project is called django-validation. It basicly allows one to write a Newforms form class, and generate client-side validation code for this form in a template. Currently only CharField validation is implemented, more should follow soon and is easy to add.

Next to validation of built-in field types, one can also add code to validate custom fields. This can be done inside an inner class of the field class.

The current release is very alpha-grade software, a lot of enhancements could be done, and most certainly more standard field type validators should be written. Next to this, field type inheritance isn’t supported for now (so if your field type A inherits CharField, no CharField validation will be done), this should change soon.

Patches are, obviously, very welcome!

Here’s a sample how to use it. First we define a very basic form:

class TestForm(forms.Form):
    first_name = forms.CharField(max_length=128)
    test = TestField(required_value=u'I like django-validation')

This form uses a custom class (just for demonstration purposes). This class only performs client-side validation, no clean() function is provided, although in real field types this should obviously be added. More information can be found in the inline comments:

from validation.templatetags.validation import add_error
class TestField(forms.CharField):
    def __init__(self, *args, **kwargs):
        if not 'required_value' in kwargs.keys():
            raise Exception, 'required_value should be provided'
        self.required_value = kwargs['required_value']
        del kwargs['required_value']
        super(TestField, self).__init__(*args, **kwargs)

    class ClientValidator:
        '''
        This inner class knows how to generate Javascript validation code for this field type.
        The code will be pasted inside a function block. There is at least one assigned variable, 'field',
        which is the DOM element we got to validate.

        More parameters can be defined in the 'parameters' attribute. These parameters will be added
        to the Javascript function prototype, and the value of the form field parameter value will be
        assigned.

        We need to define the field class name, so the django-validation code can generate suitable
        function names.
        '''
        parameters = ('required_value', )
        field_class = 'TestField'

        def render(self, output):
            '''
            The render function should output Javascript code to check the value of the 'field' element.
            It is called inside a Javascript function scope.

            output is a StringIO object. Normally only write or writelines calls should be used.
            '''
            output.write('value = field.value;\n')
            output.write('if(value != required_value) {\n')
            # This error message should be internationalized.
            # See the add_error documentation.
            add_error(output, 'error_msg', 'Field value should be %(value)d.', (('%(value)d', 'required_value'), ))
            output.write('    return [error_msg];\n')
            output.write('}\n')

Finally, here’s how to use it inside a template (this must be one of the worse HTML/Javascript snippets I ever wrote):

{% load validation %}
<html>
<body>
    <form>
        {{ form.as_p }}
        <p><input type="submit" onclick="return testform(this.form);" />
    </form>
    <div id="errors"></div>
    {% validation_js form 'validate_testform' %}
    <script type="text/javascript">
        function testform(form) {
            valid = true;
            errors = validate_testform(form);
            err = "<ul>";
            for(field in errors) {
                if(errors[field] != null) {
                    err += '<li>' + field + ': ' + errors[field][0] + '</li>';
                    valid = false;
                }
            }
            err += '</ul>';
            if(valid)
                err = 'Form is valid';
            document.getElementById('errors').innerHTML = err;
            return false;
        }
    </script>
</body>
</html>

The current code is available in a git repository. Enjoy!

]]>
http://eikke.com/django-validation-an-introduction/feed/ 6
Django generic AJAX form validation http://eikke.com/django-generic-ajax-form-validation/ http://eikke.com/django-generic-ajax-form-validation/#comments Mon, 31 Dec 2007 13:20:26 +0000 Nicolas http://eikke.com/django-generic-ajax-form-validation/ I just created a generic view for Django which allows a developer to easily add AJAX-style form validation to a newforms based form.

The system needs one server-side view, and some client-side JavaScript. You can find the view code in my Django snippets Git repository. The view only works with POST requests. It takes a standard HttpRequest and some options:

  • form_class: this parameter defines the newforms class to validate against. It can be specified in the extra args parameter of the view’s urlconf. If you don’t specify it, the ‘form_class’ POST field will be used. If this doesn’t exist either, an exception is raised. The parameter can be a newforms form instance, a string, or a class (which should be a subclass of BaseForm).
  • format: the serialization format to use. Currently only ‘json’ is supported.
  • args: extra argument list to provide to the form constructor (shouldn’t be provided in most cases)
  • kwargs: extra argument dics to provide to the form constructor (shouldn’t be provided in most cases)

Next to the server-side view you’ll need some pretty basic JavaScript code on client side. I use JQuery and the JQuery Form plugin. Here’s some sample code, assuming the form ID is ‘my_form’, and form fields are represented like this:

<p id="{{ form.field.name }}_container"><label for="{{ form.field.auto_id }}">{{ form.field.label|capfirst }}:</label>{{ form.field }}
{% if form.field.errors %}<span id="{{ form.field.name }}_error" class="error">{{ form.field.errors.0 }}</span>{% endif %}
</p>

Here’s the corresponding JavaScript code:

function do_something() {
}
function process_validation(data) {
    if(data['form_valid'] == true) {
        do_something();
        return;
    }
    for(var field in data["errors"]) {
        errors = data["errors"][field]
        if(errors.length > 0) {
            error = errors[0];
            if($("#" + field + "_error").length == 0) {
                s = $("<br /><span style=\"display: none;\" id=\"" + field + "_error\" class=\"error\">" + error + "</span>");
                $("#" + field + "_container").append(s);
            }
            $("#" + field + "_error").html(error).fadeIn("slow");
        }
    }
}
function validate_form(data) {
    data.push({name: 'form_class', value: 'project.application.forms.ApplicationForm'});
    $.post("{% url validate_form %}", data, process_validation, "json");
}
$(document).ready(function() {
    $("#my_form").submit(function() {
        data = $("#my_form").formToArray();
        $(".error").fadeOut("slow");
        validate_form(data);
        return false;
    });
});

Obviously this should be changed to suit your needs.

I hope this code can be useful for someone…

]]>
http://eikke.com/django-generic-ajax-form-validation/feed/ 10
Filesystem issues and django-couchdb work http://eikke.com/filesystem-issues-and-django-couchdb-work/ http://eikke.com/filesystem-issues-and-django-couchdb-work/#comments Sun, 30 Dec 2007 01:47:22 +0000 Nicolas http://eikke.com/filesystem-issues-and-django-couchdb-work/ Last night, when shutting down my laptop (which had been up for quite a long time because of suspend/resume niceness), it crashed. I don’t know what exactly happened: pressed the GNOME’s logout button, applications were closed, until only my background was visible, then the system locked up, so I suspect my X server (some part of it, GPU driver (fglrx) might be the bad guy). I was able to sysrq s u o, so I thought everything would be relatively fine.

This morning I powered on my system, and while booting, fsck of some partitions was taking a rather long time. It’s pretty normal fsck was taking somewhat longer, but not thát long… I’m using JFS on most logical volumes.

When the consistency check of my /home partition was done, a whole load of invalid files was displayed and later on moved to lost+found: 34068 files. Once booted, I scanned my filesystems again, rebooted, logged in, started X. Everything started fine, until I launched Evolution: it presented my the ‘initial run’ wizard. Other issues (on first sight): all Firefox cookies were gone, and Pidgin’s blist.xml was corrupted. When using my old computer (which had frequent lockups on heavy IO usage) these last 2 issues happened a lot too, which is highly annoying, especially the blist.xml thing as I can’t see any reason to keep this file opened for long periods?

Luckily I was able to get my Evolution up and running again by restoring it’s GConf settings and ~/.evolution using some old backup (15/10/07). I guess I should backup more regularly… Next to this I hope I won’t find any other corrupted files, so the ones in lost+found are just Evolution email files and Firefox caches.

Anyway, here’s a screenshot displaying some of the initial and hackish work I’ve done this evening on integrating Django and CouchDB as I wrote about yesterday:

Django and CouchDB first shot

As you can see, currently I’m able to edit fields of an object. There’s one major condition: an object with the given ID should already exist in the ‘database’ which makes the current code rather useless, but hey ;-) I’ll add object creation functionality later tonight or tomorrow.

Current code is very expensive too, doing way too many queries to CouchDB, mainly in client.py. This most certainly needs work.

Upgraded my WordPress installation to the latest release, 2.3.2, in about 5 seconds. Got to love svn switch (although maybe I should start using git-svn for this installation too and git-pull the release branch in my local copy).

]]>
http://eikke.com/filesystem-issues-and-django-couchdb-work/feed/ 9
CouchDB with Python http://eikke.com/couchdb-with-python/ http://eikke.com/couchdb-with-python/#comments Sat, 29 Dec 2007 01:25:52 +0000 Nicolas http://eikke.com/couchdb-with-python/ Today I’ve been investigating CouchDB a little better (only heard some rumors about it before). It’s actually a pretty nice technology which can, in some places, be pretty useful… I tend to compare it to caching serialized PHP associative arrays or Python dict’s in a Memcached server using some specific prefixes, except it’s not really memory-based (it’s persistent), you get a complete query interface (views), there’s dataset versioning support (!), etc. While writing this I start to wonder what similarities I ever saw between CouchDB and a Python pickled dict in Memcached…

Anyway, one use case I saw was site user profiles: profile data is most of the time not relational at all, so why store it in a relational database, which makes it sometimes rather hard to add extra profile information fields, unless you use some dirty ‘save serialized form’ trick, which renders your data unqueryable? Storing profile information (using eg. a user’s primary email address or login name as key for the user profile document) in CouchDB allows you to extend the profile “schema” easily: just add a field to your profile editting form, make sure it’s processed server-side an stored in the profile document, and add some extra code to your profile rendering template so the extra field get displayed too. No need to alter SQL tables at all!

As in my last site project I also have some sort of user profiles, I was thinking about using CouchDB for storage of these objects. As the site is written using Django, it would be nice to be able to define a standard Django model for the profile, which would be stored in CouchDB, not insome SQL server. This way you can still enjoy newforms goodness, among others.

So I started some new project, called django-couchdb, which should in time provide a model base class (similar to django.db.models.Model), corresponding managers to query the data, and so on. I don’t know (yet) whether all this is possible to achieve, anyway, I started by creating a very basic Python class which allows you to access a CouchDB server in a very Pythonic way: using dicts. A Server is a dict consisting of Databases, a Database is a dict of Documents. All this implemented thanks to the goodness of the DictMixin base class.

The client is not finished yet, at least 3 TODO items are on my list:

  • Error/Exception handling
  • Revision handling
  • View support

Currently there is no support for any of these. Views should be easy to add, error handling a little harder. I think revision handling is the hardest part, escpecially on figuring out how to provide this functionality in a Pythonic manner.

You can find the current code in this Git repository. Patches or external branches are very welcome!

By the way: the website I referred to before has been launched. It’s only of any use (well, maybe) for dutch-speaking users though. You can visit it here. Yes, the template will change.

]]>
http://eikke.com/couchdb-with-python/feed/ 5
Django domain redirect middleware http://eikke.com/django-domain-redirect-middleware/ http://eikke.com/django-domain-redirect-middleware/#comments Wed, 26 Dec 2007 15:02:12 +0000 Nicolas http://eikke.com/2007/12/26/django-domain-redirect-middleware/ Most web developers know it’s possible to serve one site on several domains or subdomains, using eg. the ServerAlias Apache directive. Sometimes this behaviour is not wanted: you want your main domain to be “foo.tld”, although “www.foo.tld” should work too, and maybe even some completely different domains.

This way it’s possible to have permalinks, and you won’t get bad points from search engine spiders who don’t like the same content to be available on several URIs.

In Django there’s the PREPEND_WWW setting, which will force all requests to be redirected to www.foo.bar when coming in on foo.bar, etc. This functionality is rather limited though. As I wanted to be able to have one unique main domain in my new application, I wrote a middleware which accomplishes this in a very generic way, using the django.contrib.sites framework. You need to add this middleware before all others in your settings file, even before the CommonMiddleware.

Here’s the code:

from django.contrib.sites.models import Site
from django.http import HttpResponsePermanentRedirect
from django.core.urlresolvers import resolve
from django.core import urlresolvers
from django.utils.http import urlquote

class DomainRedirectMiddleware(object):
    def process_request(self, request):
        host = request.get_host()
        site = Site.objects.get_current()

        if host == site.domain:
            return None

        # Only redirect if the request is a valid path
        try:
            # One issue here: won't work when using django.contrib.flatpages
            # TODO: Make this work with flatpages :-) 
            resolve(request.path)
        except urlresolvers.Resolver404:
            return None

        new_uri = '%s://%s%s%s' % (
                request.is_secure() and 'https' or 'http',
                site.domain,
                urlquote(request.path),
                (request.method == 'GET' and len(request.GET) > 0) and '?%s' % request.GET.urlencode() or ''
            )

        return HttpResponsePermanentRedirect(new_uri)

Make sure you got the sites framework set up correctly when using this! As noted in the code, this doesn’t work with the Flatpages framework yet, this is TODO.

]]>
http://eikke.com/django-domain-redirect-middleware/feed/ 7
Two Django snippets http://eikke.com/two-django-snippets/ http://eikke.com/two-django-snippets/#comments Wed, 26 Dec 2007 02:11:44 +0000 Nicolas http://eikke.com/2007/12/26/two-django-snippets/ Last 2-3 days I’ve been working on this new site project. As (almost) all web projects I started last 2 years, I’m using the Django framework to develop the site, as I just love it for several reasons.

Tonight I’d like to share 2 snippets. The first one is one I use quite regularly. It’s a replacement for django.shortcuts.render_to_response, which requires one to always add a RequestContent keyword argument to be able to access MEDIA_URL etc in templates.

This replacement (which I mostly put in utils/shortcuts.py) is completely API-compatible with the default render_to_response implementation, but if you pass it a request object as first parameter (and no context_instance), it automaticly uses a RequestContext.

from django.shortcuts import render_to_response as real_render_to_response
from django.http import HttpRequest
from django.template.context import RequestContext

def render_to_response(*args, **kwargs):
    # Check old API
    if len(args) > 0 and not isinstance(args[0], HttpRequest):
        return real_render_to_response(*args, **kwargs)
    if not kwargs.get('context_instance', None):
        kwargs['context_instance'] = RequestContext(args[0])

    return real_render_to_response(*args[1:], **kwargs)

The second one is an custom form which can be used with the django-contact-form application. It automaticly uses the name and email address of the user if logged in, otherwise provides the standard text input fields.

It might be a good example of how to implement a custom widget, and how to set per-form-instance values of widgets.

Do note you will need to change some things around line 29.

class ConstOrTextInput(forms.TextInput):
    def __init__(self, *args, **kwargs):
        super(ConstOrTextInput, self).__init__(*args, **kwargs)
        self.const_value = None

    def value_from_datadict(self, *args, **kwargs):
        if not self.const_value:
            return super(forms.TextInput, self).value_from_datadict(*args, **kwargs)
        return self.const_value

        def render(self, *args, **kwargs):
            if not self.const_value:
                return super(forms.TextInput, self).render(*args, **kwargs)
            else:
                from django.utils.safestring import mark_safe
                return mark_safe(u'' % self.const_value)

class UserdataContactForm(ContactForm):
    name = forms.CharField(max_length=100,
                                           widget=ConstOrTextInput(attrs=attrs_dict),
                                           label=u'Your name')
    email = forms.EmailField(widget=ConstOrTextInput(attrs=dict(attrs_dict,
                                           maxlength=200)),
                                           label=u'Your email address')

    def __init__(self, data=None, request=None, *args, **kwargs):
        super(UserdataContactForm, self).__init__(data, request, *args, **kwargs)
        if request.user.is_authenticated():
            self.fields['name'].widget.const_value = request.user.get_profile().get_display()
            self.fields['email'].widget.const_value = request.user.email
        else:
            self.fields['name'].widget.const_value = None
            self.fields['email'].widget.const_value = None

    def from_email(self):
        if self.request and self.request.user.is_authenticated():
            return self.request.user.email
        else:
            return super(UserdataContactForm, self).from_email

I added this to the end of the forms.py from the django-contact-form application, if you place it elsewhere, some more changes might be necessary.

I hope this is useful for at least someone!

]]>
http://eikke.com/two-django-snippets/feed/ 2