django: adding * to every required field

It is almost a standard to mark required fields on a web form with *. While working on django newforms (now forms) I realized quite late that the as_* methods of forms do not mark required fields with *. A straight forward way would have been to write an inclusion tag and just render the form, as mentioned; IF I was starting the app. But when you evolve your app from a single page, almost all of your forms are going to be rendered using as_* methods. And if you are as lazy as me, you’ll definitely get cramps just by thinking about all the possible changes.

So i started thinking, “How do I mark all the required fields with * while keeping the as_* methods?”. Determined not to change the templates; I sniffed around the django code for a couple of hours, tried many variation and finally found a lazy (not too pretty :) ) way around this issue. The code for this solution is following,

from django.newforms.forms import BoundField
__init__temp = BoundField.__init__
 
def __my_init__(self, form, field, name):
 
      __init__temp(self, form, field, name)
 
      if self.field.required:
 
            self.label += '*'
 
BoundField.__init__ = __my_init__

For those who are in a hurry, copy and paste the above code at the top of your forms.py file.

Now for the explanation. When a BoundField is created, it gets its label from the field. If we can somehow hook into the __init__ method of BoundField and change the label, we an get our desired result. In this code snippet,

  • save the BoundField.__init__ method in __init__temp__ and replace it with my own implementation (__my__init__).
  • In __my__init__, call the old __init__ method (saved in __init__temp__)
  • append ‘*’ to the BoundField.label if field is required.

This way, you dont have to change anything in your templates and yet mark all required fields as ‘*’. I am not sure if this is an smart hack or an ugly hack? Writing an inclusion template seems the right approach in long-term. But if you are looking for a quick solution, this serves the purpose.

Related posts:

  1. django: Hacking django object_list to take list of templates

13 Comments

  1. Andrew says:

    I’m confused. How does putting this in my forms.py alter the behavior of BoundField?

  2. Adil Saleem says:

    Andrew,

    A BoundField object is created for every field in your form object. This code replaces the normal __init__ method of BoundField with __my_init__. So when an object of BoundField is created, __my_init__ will be called instead of __init__. In this new method, I call the original __init__ first for proper initialization then change the BoundField label if field is required.

  3. With latest SVN the code above will issue a DeprecationWarning (you should import django.forms.forms); anyway you may want to look at the AdminField class in admin sources in django (django/contrib/admin/options.py), since the admin app marks required fields with bold text and does this in a cleaner way (basically manipulating the .label attribute of BoundField). And you can consider marking the * with a proper class so it can be styled with CSS.

  4. CpILL says:

    Actually, its not mentioned how you check for a required field on those pages in a forms template file? Its actually a bit of a pain in the back side and this hack seems the only quick solution as far as I can tell…?!

  5. lgespee says:

    It is also possible to access this property from within a template, using field.field.required.

    Like so:

    {% for field in form %}

    {{ field.label_tag }} {% if field.field.required %}*{% endif %}
    {{ field }}

    {% endfor %}

    I left the error displaying out not to make the example to complex.
    More info can be found at http://docs.djangoproject.com/en/dev/topics/forms/ .

  6. lgespee says:

    @lgespee
    Please corrent the typo I made:
    … the example to complex. …
    … the example too complex. …

    Thanks

  7. wow gold says:

    Good post,This was exactly what I needed to read today! I am sure this has relevance to many of us out there.

  8. Jessi says:

    Nice stuff, thank you

  9. ambulans says:

    Hi, very good web site. Thanks.

  10. UK SEO says:

    THis works well, but Igespee’s form field customisation is probably better practice.

    Worth raising as a ticket to adjust the default behaviour of the as_* options in Django though, as it’s always valutable to have required or not in the class.

  11. GLENN HAYES says:

    I want to thank you for taking time to post this, it was really helpful.

  12. Great post! These are necessary things to stay in mind, it’s usually easy to forget concerning the easy things once you get consumed by a project.

  13. lace wigs says:

    I see, Thanks.

Leave a Reply