django forms and where to add dynamic choices
October 2021
Sun Mon Tue Wed Thu Fri Sat
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
About
This site is an effort to share some of the base knowledge I have gathered through all this years working with Linux, FreeBSD, OpenBSD, Python or Zope, among others. So, take a look around and I hope you will find the contents useful.
Recent Entries
Recent Comments
Recent Trackbacks
Categories
OpenBSD (9 items)
BSD (0 items)
FreeBSD (19 items)
Linux (3 items)
Security (3 items)
Python (22 items)
Zope (13 items)
Daily (144 items)
e-shell (9 items)
Hacks (14 items)
PostgreSQL (3 items)
OSX (8 items)
Nintendo DS (0 items)
enlightenment (0 items)
Apache (3 items)
Nintendo Wii (1 items)
Django (24 items)
Music (12 items)
Plone (7 items)
Varnish (0 items)
Lugo (2 items)
Sendmail (0 items)
europython (7 items)
Cherokee (1 items)
self (1 items)
Nature (1 items)
Hiking (0 items)
uwsgi (0 items)
nginx (0 items)
cycling (10 items)
Networking (1 items)
DNS (0 items)
Archives

Syndicate this site (XML)

RSS/RDF 0.91

22 enero
2009

django forms and where to add dynamic choices

is it forms.py, is it views.py, where?

In django, you can use the so-called ModelForms to generate a form directly from a model definition. This is pretty useful, as you can have a models.py file like, for example:

class Project(models.Model):
    name = models.CharField('Name of the project', max_length=100)
    code = models.CharField('Code number of the project', max_length=10)
    creator = models.ForeignKey(User, related_name='created_projects')
    maintainer = models.ManyToManyField(User, related_name='maintained_projects')

In this case we are creating a Project model, that is, a model to define information we will handle for those projects (this is an example, of course it would have more fields). The first two fields are CharFields (text fields where we will save the name and a numeric code for the project). The next two fields are ForeignKey and ManyToManyField fields (links to another model, this time User, which is django.contrib.auth.models.User, that is, the default django user model).

I've added two different relations to the User model, one will be the creator of the project, the other one the maintainer (or maintainers) of the project.

Now, back to ModelForms, I can create an HTML form just adding something like that to the app forms.py:

from myproject.myapp.models import Project

class ProjectForm(forms.ModelForm):
    class Meta:
        model = Proyecto

Once you've defined the form, you can get an html form just doing:

from myproject.myapp.forms import ProjectForm

myform = ProjectForm()

and you can use the form as described in the forms documentation (I'll not step there in detail).

But there is one problem with that approach. Imagine I've created two different groups (using django.contrib.auth.models.Group), let's call them project creators and project maintainers. Only users in the project creators group should be available in the creator field and users in the project maintainers group should be available to select for the the maintainer field.

Well, that's easy, we only have to modify a bit our forms.py:

from myproject.myapp.models import Project
from django.contrib.auth.models import Group

class ProjectForm(forms.ModelForm):

    creator_choices = [(c.id, c.username) for c in Group.objects.get(name__icontains='creator').user_set.all()]
    maintainer_choices = [(m.id, m.username) for m in Group.objects.get(name__icontains='maintainer').user_set.all()]

    creator = forms.ChoiceField(required=True, label='Project creator', choices=creator_choices)
    maintainer = forms.MultipleChoiceField(required=True, label='Project maintainer(s)', choices=maintainer_choices)

    class Meta:
        model = Proyecto

Ok, what we've got here is that I've overwrote or replaced the default creator and maintainer fields automatically generated by django, setting two new fields. This allow me to set certain default options for the fields, like the list of choices available (which I've generated searching for users in the needed groups).

Now a user will be able to select only users in the project creators group in the creator field and users in the project maintainers group in the maintainer field.

BUT, there is a problem with that. Doing it that way, the list of choices for each field will be generated on startup time (when you launch the django development server or apache or lighttpd or nginx or whatever you are using). That means that if you add a new user to the maintainers group, it will not appear in the maintainer field until you restart your server!

To avoid that, we will need to add the current available choices before using the form, overwriting the default list of choices:

from myproject.myapp.forms import ProjectForm
from django.contrib.auth.models import Group

creator_choices = [(c.id, c.username) for c in Group.objects.get(name__icontains='creator').user_set.all()]
maintainer_choices = [(m.id, m.username) for m in Group.objects.get(name__icontains='maintainer').user_set.all()]

creator = forms.ChoiceField(required=True, label='Project creator', choices=creator_choices)
maintainer = forms.MultipleChoiceField(required=True, label='Project maintainer(s)', choices=maintainer_choices)

myform = ProjectForm()

myform.fields['creator'].choices = creator_choices
myform.fields['maintainer'].choices = maintainer_choices

And that's it! This way the auto-generated html form will show up-to-date information in the select combos.

Posted by wu at 14:24 | Comments (1) | Trackbacks (0)
<< I've got flu | Main | OpenBSD, PyCha and the Memory Error. >>
Comments
Re: django forms and where to add dynamic choices

This is awesome! Exactly what I was looking for! There is one oddity in the code though. Shouldn't the lines that read "model = Proyecto" be "model = Project" ?

Thank you much, this worked perfectly!

Posted by: Shane C. Mason at abril 27,2009 00:09
Re: django forms and where to add dynamic choices

Yes, you are right (my fault, as the code is a copy of current code within one of my projects, which is coded in spanish :))

Thnx for the correction.

Posted by: Wu at abril 27,2009 09:55
Re: django forms and where to add dynamic choices

Nice one Wu. Though, in your second example, you could've used the ``ModelChoiceField`` and ``ModelMultipleChoiceField`` like so:


class ProjectForm:
creator = forms.ModelChoiceField(queryset=User.objects.filter(groups__name__icontains='creator')
maintainer = forms.ModelMultipleChoiceField(queryset=User.objects.filter(groups__name__icontains='maintainer')

class Meta:
model = Project

Like you said, this'll evaluate the querysets when your form is created. For dynamic choices, I prefer to override the form's ``__init__`` method, and create them there:

class ProjectForm:
class Meta:
model = Project

def __init__(self, *args, **kwargs):
super(ProjectForm, self).__init__(*args, **kwargs)
self.fields['creator'].queryset = User.objects.filter(groups__name__icontains='creator')
self.fields['maintainer'] = User.objects.filter(groups__name__icontains='maintainer')

Cheers!

Posted by: Stan at mayo 07,2009 16:15
Re: django forms and where to add dynamic choices

I applied this example and I am getting: "is not one of the available choices".

Posted by: Ryan at febrero 06,2011 19:55
Re: django forms and where to add dynamic choices

Hi Ryan, that error could be related to the version of django you are using. This post is 2 years old now and probably some things wouldn't apply to recent django versions (I hadn't the time to check with new versions of django, so I can't tell about it).

Thnx for your comment.

Posted by: Wu at febrero 09,2011 09:26
Re: django forms and where to add dynamic choices

Thanks! Banged my head on the desk all day yesterday thinking it was some odd queryset caching thing and could not figure this out. This solution seems awkward, but it works I suppose.

Posted by: woodb at junio 17,2011 17:29
Re: django forms and where to add dynamic choices

So good !!! Thanks

Muy bueno, gracias ;-)

Posted by: serfer2 at noviembre 02,2011 10:47
Re: django forms and where to add dynamic choices

Could you please expalain how to present this form in html?
simple {{form}} does not fit
and on {{form.field['%s' % company.id] }} gives me an error

Here is my model



class ChoiceForm(forms.Form):
def __init__(self,companies,types,*args, **kwargs):
forms.Form.__init__(self,*args, **kwargs)
for company in companies:
label = company.name
self.fields['company_%s' % company.id] = forms.BooleanField(label=label, required= False)
#self.fields['%s' % company.id] = forms.BooleanField(label=label, required = False)
for typ in types:
label = typ.name
self.fields['type_%s' % typ.id] = forms.BooleanField(label=label, required= False)
def setData(self, companies, types):
for element in companies:
label = element.name
self.fields['company_%s' % element.id] = forms.BooleanField(label=label,\
required= False, initial= True)
for element in types:
label = element.name
self.fields['type_%s' % element.id] = forms.BooleanField(label=label,\
required= False, initial= True)

Posted by: Dmitry at enero 29,2012 19:26
Re: django forms and where to add dynamic choices

@Dmitry: I'm sorry, but I'm not sure what you are exactly trying to do... and I don't understand how your code and question could fit in this post anyway, so I can't help you really.

Posted by: Wu at enero 31,2012 20:18
Re: django forms and where to add dynamic choices

dgd

Posted by: dsada at septiembre 17,2021 07:48
Trackbacks
Please send trackback to:http://blog.e-shell.org/130/tbping
There are no trackbacks.
Post a comment