ManyToManyField and Ordered fields in Django ModelForms
Monday, June 15th, 2009I was working on some code and realized that ManyToManyFields always show up last in a ModelForm, regardless if you specify the order in the Meta fields property. Apparently this is due to be fixed in Django 1.1 which is right around the corner.. unfortunately I’m on 1.0 and feel anxious about moving 10+ sites to 1.1 beta right at this moment. I also felt it was a bit inappropriate to diff my Django source.
Please be aware that this is a hack. It is not an optimal solution. Stuff like form.as_* will NOT work with the solution below. All this does is add a property called ordered_fields to your ModelForm which implements the correct behavior.
# models.py
class Bar(models.Model):
pass
class Foo(models.Model):
# ordinarily, Django 1.0 would list the regular_field first and all M2Ms last
many_to_many = models.ManyToManyField('Bar', related_name='foos')
regular_field = models.CharField(max_length=10)
# forms.py
class FooForm(forms.ModelForm):
def ordered_fields(self):
list = []
for field_name in self._meta.fields:
list.append(self[field_name])
return list
class Meta:
model = Foo
fields = ('many_to_many',
'regular_field',)
#Template:
<form action="{{ app_path }}" method="post" id="foo-form">
<fieldset class="module aligned ()">
{% for field in form.ordered_fields %}
<div class="form-row thin wide ()">
{{ field.label_tag }}
{{ field }}
{{ field.errors }}
{% if field.help_text %}
<p class="help">{{ field.help_text }}</p>
{% endif %}
</div>
{% endfor %}
</fieldset>
<div class="submit-row aligned ()">
<input class="default" type="submit" value="Send" />
</div>
</form>