Skip to content

Commit

Permalink
Fixed #8164 -- Fields on a ModelForm are now ordered in the order spe…
Browse files Browse the repository at this point in the history
…cified in the fields attribute of the ModelForm's Meta class. Thanks to Alex Gaynor for the patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@10062 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
freakboy3742 committed Mar 15, 2009
1 parent 24b9c65 commit 7be4b9a
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 14 deletions.
6 changes: 4 additions & 2 deletions django/forms/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ def fields_for_model(model, fields=None, exclude=None, formfield_callback=lambda
fields will be excluded from the returned fields, even if they are listed
in the ``fields`` argument.
"""
# TODO: if fields is provided, it would be nice to return fields in that order
field_list = []
opts = model._meta
for f in opts.fields + opts.many_to_many:
Expand All @@ -162,7 +161,10 @@ def fields_for_model(model, fields=None, exclude=None, formfield_callback=lambda
formfield = formfield_callback(f)
if formfield:
field_list.append((f.name, formfield))
return SortedDict(field_list)
field_dict = SortedDict(field_list)
if fields:
field_dict = SortedDict([(f, field_dict[f]) for f in fields if (not exclude) or (exclude and f not in exclude)])
return field_dict

class ModelFormOptions(object):
def __init__(self, options=None):
Expand Down
28 changes: 27 additions & 1 deletion docs/topics/forms/modelforms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,8 @@ model fields:

2. Use the ``fields`` attribute of the ``ModelForm``'s inner ``Meta``
class. This attribute, if given, should be a list of field names
to include in the form.
to include in the form. The form will render the fields in the same
order they are specified in the ``fields`` attribute.

3. Use the ``exclude`` attribute of the ``ModelForm``'s inner ``Meta``
class. This attribute, if given, should be a list of field names
Expand Down Expand Up @@ -336,6 +337,31 @@ parameter when declaring the form field::
... class Meta:
... model = Article

Changing the order of fields
----------------------------

By default, a ``ModelForm`` will render fields in the same order that
they are defined on the model, with ``ManyToManyField``s appearing last.
If you want to change the order in which fields are rendered, you can
use the ``fields`` attribute on the ``Meta`` class.

The ``fields`` attribute defines the subset of model fields that will be
rendered, and the order in which they will be rendered. For example given this
model::

class Book(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(max_length=100)

the ``author`` field would be rendered first. If we wanted the title field
to be rendered first, we could specify the following ``ModelForm``::

>>> class BookForm(ModelForm):
... class Meta:
... model = Book
... fields = ['title', 'author']


Overriding the clean() method
-----------------------------

Expand Down
45 changes: 34 additions & 11 deletions tests/modeltests/model_forms/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,12 @@ def __unicode__(self):
# If PIL is not available, ImageField tests are omitted.
from PIL import Image, _imaging
test_images = True

class ImageFile(models.Model):
def custom_upload_path(self, filename):
path = self.path or 'tests'
return '%s/%s' % (path, filename)

description = models.CharField(max_length=20)
image = models.ImageField(storage=temp_storage, upload_to=custom_upload_path,
width_field='width', height_field='height')
Expand All @@ -120,15 +120,15 @@ def custom_upload_path(self, filename):

def __unicode__(self):
return self.description

class OptionalImageFile(models.Model):
def custom_upload_path(self, filename):
path = self.path or 'tests'
return '%s/%s' % (path, filename)

description = models.CharField(max_length=20)
image = models.ImageField(storage=temp_storage, upload_to=custom_upload_path,
width_field='width', height_field='height',
width_field='width', height_field='height',
blank=True, null=True)
width = models.IntegerField(editable=False, null=True)
height = models.IntegerField(editable=False, null=True)
Expand All @@ -138,7 +138,7 @@ def __unicode__(self):
return self.description
except ImportError:
test_images = False

class CommaSeparatedInteger(models.Model):
field = models.CommaSeparatedIntegerField(max_length=20)

Expand Down Expand Up @@ -176,16 +176,16 @@ class Book(models.Model):
title = models.CharField(max_length=40)
author = models.ForeignKey(Writer, blank=True, null=True)
special_id = models.IntegerField(blank=True, null=True, unique=True)

class Meta:
unique_together = ('title', 'author')

class ExplicitPK(models.Model):
key = models.CharField(max_length=20, primary_key=True)
desc = models.CharField(max_length=20, blank=True, unique=True)
class Meta:
unique_together = ('key', 'desc')

def __unicode__(self):
return self.key

Expand Down Expand Up @@ -331,6 +331,29 @@ def __unicode__(self):
<tr><th><label for="id_slug">Slug:</label></th><td><input id="id_slug" type="text" name="slug" maxlength="20" /></td></tr>
<tr><th><label for="id_checkbox">Checkbox:</label></th><td><input type="checkbox" name="checkbox" id="id_checkbox" /></td></tr>
# test using fields to provide ordering to the fields
>>> class CategoryForm(ModelForm):
... class Meta:
... model = Category
... fields = ['url', 'name']
>>> CategoryForm.base_fields.keys()
['url', 'name']
>>> print CategoryForm()
<tr><th><label for="id_url">The URL:</label></th><td><input id="id_url" type="text" name="url" maxlength="40" /></td></tr>
<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr>
>>> class CategoryForm(ModelForm):
... class Meta:
... model = Category
... fields = ['slug', 'url', 'name']
... exclude = ['url']
>>> CategoryForm.base_fields.keys()
['slug', 'name']
# Old form_for_x tests #######################################################
>>> from django.forms import ModelForm, CharField
Expand Down Expand Up @@ -1331,8 +1354,8 @@ def __unicode__(self):
True
# Unique & unique together with null values
>>> class BookForm(ModelForm):
... class Meta:
>>> class BookForm(ModelForm):
... class Meta:
... model = Book
>>> w = Writer.objects.get(name='Mike Royko')
>>> form = BookForm({'title': 'I May Be Wrong But I Doubt It', 'author' : w.pk})
Expand Down

0 comments on commit 7be4b9a

Please sign in to comment.