Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #8164 -- Fields on a ModelForm are now ordered in the order spe…

…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...
commit 7be4b9a4c005639f03fcd096c3a53fffcb7f210c 1 parent 24b9c65
Russell Keith-Magee authored March 15, 2009
6  django/forms/models.py
@@ -149,7 +149,6 @@ def fields_for_model(model, fields=None, exclude=None, formfield_callback=lambda
149 149
     fields will be excluded from the returned fields, even if they are listed
150 150
     in the ``fields`` argument.
151 151
     """
152  
-    # TODO: if fields is provided, it would be nice to return fields in that order
153 152
     field_list = []
154 153
     opts = model._meta
155 154
     for f in opts.fields + opts.many_to_many:
@@ -162,7 +161,10 @@ def fields_for_model(model, fields=None, exclude=None, formfield_callback=lambda
162 161
         formfield = formfield_callback(f)
163 162
         if formfield:
164 163
             field_list.append((f.name, formfield))
165  
-    return SortedDict(field_list)
  164
+    field_dict = SortedDict(field_list)
  165
+    if fields:
  166
+        field_dict = SortedDict([(f, field_dict[f]) for f in fields if (not exclude) or (exclude and f not in exclude)])
  167
+    return field_dict
166 168
 
167 169
 class ModelFormOptions(object):
168 170
     def __init__(self, options=None):
28  docs/topics/forms/modelforms.txt
@@ -259,7 +259,8 @@ model fields:
259 259
 
260 260
 2. Use the ``fields`` attribute of the ``ModelForm``'s inner ``Meta``
261 261
    class.  This attribute, if given, should be a list of field names
262  
-   to include in the form.
  262
+   to include in the form. The form will render the fields in the same
  263
+   order they are specified in the ``fields`` attribute.
263 264
 
264 265
 3. Use the ``exclude`` attribute of the ``ModelForm``'s inner ``Meta``
265 266
    class.  This attribute, if given, should be a list of field names
@@ -336,6 +337,31 @@ parameter when declaring the form field::
336 337
    ...     class Meta:
337 338
    ...         model = Article
338 339
 
  340
+Changing the order of fields
  341
+----------------------------
  342
+
  343
+By default, a ``ModelForm`` will render fields in the same order that
  344
+they are defined on the model, with ``ManyToManyField``s appearing last.
  345
+If you want to change the order in which fields are rendered, you can
  346
+use the ``fields`` attribute on the ``Meta`` class.
  347
+
  348
+The ``fields`` attribute defines the subset of model fields that will be
  349
+rendered, and the order in which they will be rendered. For example given this
  350
+model::
  351
+
  352
+    class Book(models.Model):
  353
+        author = models.ForeignKey(Author)
  354
+        title = models.CharField(max_length=100)
  355
+
  356
+the ``author`` field would be rendered first. If we wanted the title field
  357
+to be rendered first, we could specify the following ``ModelForm``::
  358
+
  359
+    >>> class BookForm(ModelForm):
  360
+    ...     class Meta:
  361
+    ...         model = Book
  362
+    ...         fields = ['title', 'author']
  363
+
  364
+
339 365
 Overriding the clean() method
340 366
 -----------------------------
341 367
 
45  tests/modeltests/model_forms/models.py
@@ -105,12 +105,12 @@ def __unicode__(self):
105 105
     # If PIL is not available, ImageField tests are omitted.
106 106
     from PIL import Image, _imaging
107 107
     test_images = True
108  
-    
  108
+
109 109
     class ImageFile(models.Model):
110 110
         def custom_upload_path(self, filename):
111 111
             path = self.path or 'tests'
112 112
             return '%s/%s' % (path, filename)
113  
-    
  113
+
114 114
         description = models.CharField(max_length=20)
115 115
         image = models.ImageField(storage=temp_storage, upload_to=custom_upload_path,
116 116
                                   width_field='width', height_field='height')
@@ -120,15 +120,15 @@ def custom_upload_path(self, filename):
120 120
 
121 121
         def __unicode__(self):
122 122
             return self.description
123  
-    
  123
+
124 124
     class OptionalImageFile(models.Model):
125 125
         def custom_upload_path(self, filename):
126 126
             path = self.path or 'tests'
127 127
             return '%s/%s' % (path, filename)
128  
-    
  128
+
129 129
         description = models.CharField(max_length=20)
130 130
         image = models.ImageField(storage=temp_storage, upload_to=custom_upload_path,
131  
-                                  width_field='width', height_field='height', 
  131
+                                  width_field='width', height_field='height',
132 132
                                   blank=True, null=True)
133 133
         width = models.IntegerField(editable=False, null=True)
134 134
         height = models.IntegerField(editable=False, null=True)
@@ -138,7 +138,7 @@ def __unicode__(self):
138 138
             return self.description
139 139
 except ImportError:
140 140
     test_images = False
141  
-    
  141
+
142 142
 class CommaSeparatedInteger(models.Model):
143 143
     field = models.CommaSeparatedIntegerField(max_length=20)
144 144
 
@@ -176,16 +176,16 @@ class Book(models.Model):
176 176
     title = models.CharField(max_length=40)
177 177
     author = models.ForeignKey(Writer, blank=True, null=True)
178 178
     special_id = models.IntegerField(blank=True, null=True, unique=True)
179  
-    
  179
+
180 180
     class Meta:
181 181
         unique_together = ('title', 'author')
182  
-        
  182
+
183 183
 class ExplicitPK(models.Model):
184 184
     key = models.CharField(max_length=20, primary_key=True)
185 185
     desc = models.CharField(max_length=20, blank=True, unique=True)
186 186
     class Meta:
187 187
         unique_together = ('key', 'desc')
188  
-    
  188
+
189 189
     def __unicode__(self):
190 190
         return self.key
191 191
 
@@ -331,6 +331,29 @@ def __unicode__(self):
331 331
 <tr><th><label for="id_slug">Slug:</label></th><td><input id="id_slug" type="text" name="slug" maxlength="20" /></td></tr>
332 332
 <tr><th><label for="id_checkbox">Checkbox:</label></th><td><input type="checkbox" name="checkbox" id="id_checkbox" /></td></tr>
333 333
 
  334
+# test using fields to provide ordering to the fields
  335
+>>> class CategoryForm(ModelForm):
  336
+...     class Meta:
  337
+...         model = Category
  338
+...         fields = ['url', 'name']
  339
+
  340
+>>> CategoryForm.base_fields.keys()
  341
+['url', 'name']
  342
+
  343
+
  344
+>>> print CategoryForm()
  345
+<tr><th><label for="id_url">The URL:</label></th><td><input id="id_url" type="text" name="url" maxlength="40" /></td></tr>
  346
+<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr>
  347
+
  348
+>>> class CategoryForm(ModelForm):
  349
+...     class Meta:
  350
+...         model = Category
  351
+...         fields = ['slug', 'url', 'name']
  352
+...         exclude = ['url']
  353
+
  354
+>>> CategoryForm.base_fields.keys()
  355
+['slug', 'name']
  356
+
334 357
 # Old form_for_x tests #######################################################
335 358
 
336 359
 >>> from django.forms import ModelForm, CharField
@@ -1331,8 +1354,8 @@ def __unicode__(self):
1331 1354
 True
1332 1355
 
1333 1356
 # Unique & unique together with null values
1334  
->>> class BookForm(ModelForm): 
1335  
-...     class Meta: 
  1357
+>>> class BookForm(ModelForm):
  1358
+...     class Meta:
1336 1359
 ...        model = Book
1337 1360
 >>> w = Writer.objects.get(name='Mike Royko')
1338 1361
 >>> form = BookForm({'title': 'I May Be Wrong But I Doubt It', 'author' : w.pk})

0 notes on commit 7be4b9a

Please sign in to comment.
Something went wrong with that request. Please try again.