2008-03-24

DRY While Working With Choices for Forms

When creating dozens of forms with selection fields for some many-to-one or many-to-many relations, you might find that it's ineffective to create choices for the form fields from querysets formed by the relations defined by ForeignKeys and ManyToManyFields. You have to import the related models, filter the choices analogously to the limit_choices_to parameter, and form a list of tuples again and again.

To get the same choices from the model as in the admin form, you can use the following:
FIELD_CHOICES = SomeModel._meta.get_field("field_name").get_choices()

Then you can modify the text for the null-value choice, like
FIELD_CHOICES[0] = ("" _("- Choose One -"))

or even remove it:
del FIELD_CHOICES[0]

To save the selected object you can simply assign the chosen value to the foreign key, like:
new_instance = SomeModel()
new_instance.field_name_id = form.cleaned_data['field_name']
new_instance.save()

If you need to do something with the selected object, you can still live without importing specific models and filtering the entries in the same manner as limit_choices_to. To save time, you can use the following function, which returns the queryset containing all the choosable objects:
def get_related_queryset(model, field_name):
"""
Get the queryset for the choices of the field in a model
Example:
objects = get_related_queryset(SomeModel, "field_name")
"""
f = model._meta.get_field(field_name)
qs = f.rel.to._default_manager.complex_filter(f.rel.limit_choices_to)
return qs

Just put this function in one of you applications and import it whenever you need to work with forms. And have happy Easter!

No comments:

Post a Comment