Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #20000 -- Allowed ModelForm meta overrides for label, help_text…

… and error_messages
  • Loading branch information...
commit 9e50833e2293aa2734f14f9873abe4f83d03b8c6 1 parent dc9c359
Loic Bistuer authored April 04, 2013 timgraham committed June 13, 2013
56  django/forms/models.py
@@ -138,7 +138,9 @@ def model_to_dict(instance, fields=None, exclude=None):
138 138
             data[f.name] = f.value_from_object(instance)
139 139
     return data
140 140
 
141  
-def fields_for_model(model, fields=None, exclude=None, widgets=None, formfield_callback=None, localized_fields=None):
  141
+def fields_for_model(model, fields=None, exclude=None, widgets=None,
  142
+                     formfield_callback=None, localized_fields=None,
  143
+                     labels=None, help_texts=None, error_messages=None):
142 144
     """
143 145
     Returns a ``SortedDict`` containing form fields for the given model.
144 146
 
@@ -149,7 +151,16 @@ def fields_for_model(model, fields=None, exclude=None, widgets=None, formfield_c
149 151
     fields will be excluded from the returned fields, even if they are listed
150 152
     in the ``fields`` argument.
151 153
 
152  
-    ``widgets`` is a dictionary of model field names mapped to a widget
  154
+    ``widgets`` is a dictionary of model field names mapped to a widget.
  155
+
  156
+    ``localized_fields`` is a list of names of fields which should be localized.
  157
+
  158
+    ``labels`` is a dictionary of model field names mapped to a label.
  159
+
  160
+    ``help_texts`` is a dictionary of model field names mapped to a help text.
  161
+
  162
+    ``error_messages`` is a dictionary of model field names mapped to a
  163
+    dictionary of error messages.
153 164
 
154 165
     ``formfield_callback`` is a callable that takes a model field and returns
155 166
     a form field.
@@ -170,6 +181,12 @@ def fields_for_model(model, fields=None, exclude=None, widgets=None, formfield_c
170 181
             kwargs['widget'] = widgets[f.name]
171 182
         if localized_fields == ALL_FIELDS or (localized_fields and f.name in localized_fields):
172 183
             kwargs['localize'] = True
  184
+        if labels and f.name in labels:
  185
+            kwargs['label'] = labels[f.name]
  186
+        if help_texts and f.name in help_texts:
  187
+            kwargs['help_text'] = help_texts[f.name]
  188
+        if error_messages and f.name in error_messages:
  189
+            kwargs['error_messages'] = error_messages[f.name]
173 190
 
174 191
         if formfield_callback is None:
175 192
             formfield = f.formfield(**kwargs)
@@ -197,6 +214,9 @@ def __init__(self, options=None):
197 214
         self.exclude = getattr(options, 'exclude', None)
198 215
         self.widgets = getattr(options, 'widgets', None)
199 216
         self.localized_fields = getattr(options, 'localized_fields', None)
  217
+        self.labels = getattr(options, 'labels', None)
  218
+        self.help_texts = getattr(options, 'help_texts', None)
  219
+        self.error_messages = getattr(options, 'error_messages', None)
200 220
 
201 221
 
202 222
 class ModelFormMetaclass(type):
@@ -248,7 +268,9 @@ def __new__(cls, name, bases, attrs):
248 268
                 opts.fields = None
249 269
 
250 270
             fields = fields_for_model(opts.model, opts.fields, opts.exclude,
251  
-                                      opts.widgets, formfield_callback, opts.localized_fields)
  271
+                                      opts.widgets, formfield_callback,
  272
+                                      opts.localized_fields, opts.labels,
  273
+                                      opts.help_texts, opts.error_messages)
252 274
 
253 275
             # make sure opts.fields doesn't specify an invalid field
254 276
             none_model_fields = [k for k, v in six.iteritems(fields) if not v]
@@ -416,7 +438,8 @@ class ModelForm(six.with_metaclass(ModelFormMetaclass, BaseModelForm)):
416 438
     pass
417 439
 
418 440
 def modelform_factory(model, form=ModelForm, fields=None, exclude=None,
419  
-                      formfield_callback=None, widgets=None, localized_fields=None):
  441
+                      formfield_callback=None, widgets=None, localized_fields=None,
  442
+                      labels=None, help_texts=None, error_messages=None):
420 443
     """
421 444
     Returns a ModelForm containing form fields for the given model.
422 445
 
@@ -434,6 +457,13 @@ def modelform_factory(model, form=ModelForm, fields=None, exclude=None,
434 457
 
435 458
     ``formfield_callback`` is a callable that takes a model field and returns
436 459
     a form field.
  460
+
  461
+    ``labels`` is a dictionary of model field names mapped to a label.
  462
+
  463
+    ``help_texts`` is a dictionary of model field names mapped to a help text.
  464
+
  465
+    ``error_messages`` is a dictionary of model field names mapped to a
  466
+    dictionary of error messages.
437 467
     """
438 468
     # Create the inner Meta class. FIXME: ideally, we should be able to
439 469
     # construct a ModelForm without creating and passing in a temporary
@@ -449,6 +479,12 @@ def modelform_factory(model, form=ModelForm, fields=None, exclude=None,
449 479
         attrs['widgets'] = widgets
450 480
     if localized_fields is not None:
451 481
         attrs['localized_fields'] = localized_fields
  482
+    if labels is not None:
  483
+        attrs['labels'] = labels
  484
+    if help_texts is not None:
  485
+        attrs['help_texts'] = help_texts
  486
+    if error_messages is not None:
  487
+        attrs['error_messages'] = error_messages
452 488
 
453 489
     # If parent form class already has an inner Meta, the Meta we're
454 490
     # creating needs to inherit from the parent's inner meta.
@@ -738,7 +774,8 @@ def pk_is_not_editable(pk):
738 774
 def modelformset_factory(model, form=ModelForm, formfield_callback=None,
739 775
                          formset=BaseModelFormSet, extra=1, can_delete=False,
740 776
                          can_order=False, max_num=None, fields=None, exclude=None,
741  
-                         widgets=None, validate_max=False, localized_fields=None):
  777
+                         widgets=None, validate_max=False, localized_fields=None,
  778
+                         labels=None, help_texts=None, error_messages=None):
742 779
     """
743 780
     Returns a FormSet class for the given Django model class.
744 781
     """
@@ -759,7 +796,8 @@ def modelformset_factory(model, form=ModelForm, formfield_callback=None,
759 796
 
760 797
     form = modelform_factory(model, form=form, fields=fields, exclude=exclude,
761 798
                              formfield_callback=formfield_callback,
762  
-                             widgets=widgets, localized_fields=localized_fields)
  799
+                             widgets=widgets, localized_fields=localized_fields,
  800
+                             labels=labels, help_texts=help_texts, error_messages=error_messages)
763 801
     FormSet = formset_factory(form, formset, extra=extra, max_num=max_num,
764 802
                               can_order=can_order, can_delete=can_delete,
765 803
                               validate_max=validate_max)
@@ -898,7 +936,8 @@ def inlineformset_factory(parent_model, model, form=ModelForm,
898 936
                           formset=BaseInlineFormSet, fk_name=None,
899 937
                           fields=None, exclude=None, extra=3, can_order=False,
900 938
                           can_delete=True, max_num=None, formfield_callback=None,
901  
-                          widgets=None, validate_max=False, localized_fields=None):
  939
+                          widgets=None, validate_max=False, localized_fields=None,
  940
+                          labels=None, help_texts=None, error_messages=None):
902 941
     """
903 942
     Returns an ``InlineFormSet`` for the given kwargs.
904 943
 
@@ -922,6 +961,9 @@ def inlineformset_factory(parent_model, model, form=ModelForm,
922 961
         'widgets': widgets,
923 962
         'validate_max': validate_max,
924 963
         'localized_fields': localized_fields,
  964
+        'labels': labels,
  965
+        'help_texts': help_texts,
  966
+        'error_messages': error_messages,
925 967
     }
926 968
     FormSet = modelformset_factory(model, **kwargs)
927 969
     FormSet.fk = fk
29  docs/ref/forms/models.txt
@@ -5,7 +5,7 @@ Model Form Functions
5 5
 .. module:: django.forms.models
6 6
    :synopsis: Django's functions for building model forms and formsets.
7 7
 
8  
-.. function:: modelform_factory(model, form=ModelForm, fields=None, exclude=None, formfield_callback=None,  widgets=None, localized_fields=None)
  8
+.. function:: modelform_factory(model, form=ModelForm, fields=None, exclude=None, formfield_callback=None, widgets=None, localized_fields=None, labels=None, help_texts=None, error_messages=None)
9 9
 
10 10
     Returns a :class:`~django.forms.ModelForm` class for the given ``model``.
11 11
     You can optionally pass a ``form`` argument to use as a starting point for
@@ -20,11 +20,18 @@ Model Form Functions
20 20
 
21 21
     ``widgets`` is a dictionary of model field names mapped to a widget.
22 22
 
23  
-    ``localized_fields`` is a list of names of fields which should be localized.
24  
-
25 23
     ``formfield_callback`` is a callable that takes a model field and returns
26 24
     a form field.
27 25
 
  26
+    ``localized_fields`` is a list of names of fields which should be localized.
  27
+
  28
+    ``labels`` is a dictionary of model field names mapped to a label.
  29
+
  30
+    ``help_texts`` is a dictionary of model field names mapped to a help text.
  31
+
  32
+    ``error_messages`` is a dictionary of model field names mapped to a
  33
+    dictionary of error messages.
  34
+
28 35
     See :ref:`modelforms-factory` for example usage.
29 36
 
30 37
     .. versionchanged:: 1.6
@@ -35,14 +42,16 @@ Model Form Functions
35 42
     information. Omitting any definition of the fields to use will result in all
36 43
     fields being used, but this behavior is deprecated.
37 44
 
38  
-    The ``localized_fields`` parameter was added.
  45
+    The ``localized_fields``, ``labels``, ``help_texts``, and
  46
+    ``error_messages`` parameters were added.
39 47
 
40  
-.. function:: modelformset_factory(model, form=ModelForm, formfield_callback=None, formset=BaseModelFormSet, extra=1, can_delete=False, can_order=False, max_num=None, fields=None, exclude=None, widgets=None, validate_max=False, localized_fields=None)
  48
+.. function:: modelformset_factory(model, form=ModelForm, formfield_callback=None, formset=BaseModelFormSet, extra=1, can_delete=False, can_order=False, max_num=None, fields=None, exclude=None, widgets=None, validate_max=False, localized_fields=None, labels=None, help_texts=None, error_messages=None)
41 49
 
42 50
     Returns a ``FormSet`` class for the given ``model`` class.
43 51
 
44 52
     Arguments ``model``, ``form``, ``fields``, ``exclude``,
45  
-    ``formfield_callback``, ``widgets`` and ``localized_fields`` are all passed through to
  53
+    ``formfield_callback``, ``widgets``, ``localized_fields``, ``labels``,
  54
+    ``help_texts``, and ``error_messages`` are all passed through to
46 55
     :func:`~django.forms.models.modelform_factory`.
47 56
 
48 57
     Arguments ``formset``, ``extra``, ``max_num``, ``can_order``,
@@ -54,9 +63,10 @@ Model Form Functions
54 63
 
55 64
     .. versionchanged:: 1.6
56 65
 
57  
-        The ``widgets``, ``validate_max`` and ``localized_fields`` parameters were added.
  66
+        The ``widgets``, ``validate_max``, ``localized_fields``, ``labels``,
  67
+        ``help_texts``, and ``error_messages`` parameters were added.
58 68
 
59  
-.. function:: inlineformset_factory(parent_model, model, form=ModelForm, formset=BaseInlineFormSet, fk_name=None, fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, formfield_callback=None, widgets=None, validate_max=False, localized_fields=None)
  69
+.. function:: inlineformset_factory(parent_model, model, form=ModelForm, formset=BaseInlineFormSet, fk_name=None, fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, formfield_callback=None, widgets=None, validate_max=False, localized_fields=None, labels=None, help_texts=None, error_messages=None)
60 70
 
61 71
     Returns an ``InlineFormSet`` using :func:`modelformset_factory` with
62 72
     defaults of ``formset=BaseInlineFormSet``, ``can_delete=True``, and
@@ -69,4 +79,5 @@ Model Form Functions
69 79
 
70 80
     .. versionchanged:: 1.6
71 81
 
72  
-        The ``widgets``, ``validate_max`` and ``localized_fields`` parameters were added.
  82
+        The ``widgets``, ``validate_max`` and ``localized_fields``, ``labels``,
  83
+        ``help_texts``, and ``error_messages`` parameters were added.
11  docs/releases/1.6.txt
@@ -236,9 +236,14 @@ Minor features
236 236
 .. _`Pillow`: https://pypi.python.org/pypi/Pillow
237 237
 .. _`PIL`: https://pypi.python.org/pypi/PIL
238 238
 
239  
-* :doc:`ModelForm </topics/forms/modelforms/>` accepts a new
240  
-  Meta option: ``localized_fields``. Fields included in this list will be localized
241  
-  (by setting ``localize`` on the form field).
  239
+* :class:`~django.forms.ModelForm` accepts several new ``Meta``
  240
+  options.
  241
+
  242
+  * Fields included in the ``localized_fields`` list will be localized
  243
+    (by setting ``localize`` on the form field).
  244
+  * The  ``labels``, ``help_texts`` and ``error_messages`` options may be used
  245
+    to customize the default fields, see
  246
+    :ref:`modelforms-overriding-default-fields` for details.
242 247
 
243 248
 * The ``choices`` argument to model fields now accepts an iterable of iterables
244 249
   instead of requiring an iterable of lists or tuples.
59  docs/topics/forms/modelforms.txt
@@ -141,7 +141,7 @@ In addition, each generated form field has attributes set as follows:
141 141
   ``default`` value will be initially selected instead).
142 142
 
143 143
 Finally, note that you can override the form field used for a given model
144  
-field. See `Overriding the default field types or widgets`_ below.
  144
+field. See `Overriding the default fields`_ below.
145 145
 
146 146
 A full example
147 147
 --------------
@@ -388,8 +388,10 @@ include that field.
388 388
 
389 389
 .. _section on saving forms: `The save() method`_
390 390
 
391  
-Overriding the default field types or widgets
392  
----------------------------------------------
  391
+.. _modelforms-overriding-default-fields:
  392
+
  393
+Overriding the default fields
  394
+-----------------------------
393 395
 
394 396
 The default field types, as described in the `Field types`_ table above, are
395 397
 sensible defaults. If you have a ``DateField`` in your model, chances are you'd
@@ -420,38 +422,65 @@ widget::
420 422
 The ``widgets`` dictionary accepts either widget instances (e.g.,
421 423
 ``Textarea(...)``) or classes (e.g., ``Textarea``).
422 424
 
423  
-If you want to further customize a field -- including its type, label, etc. --
424  
-you can do this by declaratively specifying fields like you would in a regular
425  
-``Form``. Declared fields will override the default ones generated by using the
426  
-``model`` attribute.
  425
+.. versionadded:: 1.6
  426
+
  427
+    The ``labels``, ``help_texts`` and ``error_messages`` options were added.
  428
+
  429
+Similarly, you can specify the ``labels``, ``help_texts`` and ``error_messages``
  430
+attributes of the inner ``Meta`` class if you want to further customize a field.
427 431
 
428  
-For example, if you wanted to use ``MyDateFormField`` for the ``pub_date``
  432
+For example if you wanted to customize the wording of all user facing strings for
  433
+the ``name`` field::
  434
+
  435
+    class AuthorForm(ModelForm):
  436
+        class Meta:
  437
+            model = Author
  438
+            fields = ('name', 'title', 'birth_date')
  439
+            labels = {
  440
+                'name': _('Writer'),
  441
+            }
  442
+            help_texts = {
  443
+                'name': _('Some useful help text.'),
  444
+            }
  445
+            error_messages = {
  446
+                'name': {
  447
+                    'max_length': _("This writer's name is too long."),
  448
+                },
  449
+            }
  450
+
  451
+Finally, if you want complete control over of a field -- including its type,
  452
+validators, etc. -- you can do this by declaratively specifying fields like you
  453
+would in a regular ``Form``. Declared fields will override the default ones
  454
+generated by using the ``model`` attribute. Fields declared like this will
  455
+ignore any customizations in the ``widgets``, ``labels``, ``help_texts``, and
  456
+``error_messages`` options declared on ``Meta``.
  457
+
  458
+For example, if you wanted to use ``MySlugFormField`` for the ``slug``
429 459
 field, you could do the following::
430 460
 
431 461
     from django.forms import ModelForm
432 462
     from myapp.models import Article
433 463
 
434 464
     class ArticleForm(ModelForm):
435  
-        pub_date = MyDateFormField()
  465
+        slug = MySlugFormField()
436 466
 
437 467
         class Meta:
438 468
             model = Article
439 469
             fields = ['pub_date', 'headline', 'content', 'reporter']
440 470
 
441 471
 
442  
-If you want to override a field's default label, then specify the ``label``
443  
-parameter when declaring the form field::
  472
+If you want to override a field's default validators, then specify the
  473
+``validators`` parameter when declaring the form field::
444 474
 
445 475
     from django.forms import ModelForm, DateField
446 476
     from myapp.models import Article
447 477
 
448 478
     class ArticleForm(ModelForm):
449  
-        pub_date = DateField(label='Publication date')
  479
+        slug = CharField(validators=[validate_slug])
450 480
 
451 481
         class Meta:
452 482
             model = Article
453  
-            fields = ['pub_date', 'headline', 'content', 'reporter']
454  
-
  483
+            fields = ['pub_date', 'headline', 'content', 'reporter', 'slug']
455 484
 
456 485
 .. note::
457 486
 
@@ -597,7 +626,7 @@ example by specifying the widgets to be used for a given field::
597 626
 
598 627
     >>> from django.forms import Textarea
599 628
     >>> Form = modelform_factory(Book, form=BookForm,
600  
-                                 widgets={"title": Textarea()})
  629
+    ...                          widgets={"title": Textarea()})
601 630
 
602 631
 The fields to include can be specified using the ``fields`` and ``exclude``
603 632
 keyword arguments, or the corresponding attributes on the ``ModelForm`` inner
69  tests/model_forms/tests.py
@@ -490,7 +490,7 @@ class Meta:
490 490
                          ['slug', 'name'])
491 491
 
492 492
 
493  
-class TestWidgetForm(forms.ModelForm):
  493
+class FieldOverridesTroughFormMetaForm(forms.ModelForm):
494 494
     class Meta:
495 495
         model = Category
496 496
         fields = ['name', 'url', 'slug']
@@ -498,25 +498,74 @@ class Meta:
498 498
             'name': forms.Textarea,
499 499
             'url': forms.TextInput(attrs={'class': 'url'})
500 500
         }
  501
+        labels = {
  502
+            'name': 'Title',
  503
+        }
  504
+        help_texts = {
  505
+            'slug': 'Watch out! Letters, numbers, underscores and hyphens only.',
  506
+        }
  507
+        error_messages = {
  508
+            'slug': {
  509
+                'invalid': (
  510
+                    "Didn't you read the help text? "
  511
+                    "We said letters, numbers, underscores and hyphens only!"
  512
+                )
  513
+            }
  514
+        }
501 515
 
502 516
 
  517
+class TestFieldOverridesTroughFormMeta(TestCase):
  518
+    def test_widget_overrides(self):
  519
+        form = FieldOverridesTroughFormMetaForm()
  520
+        self.assertHTMLEqual(
  521
+            str(form['name']),
  522
+            '<textarea id="id_name" rows="10" cols="40" name="name"></textarea>',
  523
+        )
  524
+        self.assertHTMLEqual(
  525
+            str(form['url']),
  526
+            '<input id="id_url" type="text" class="url" name="url" maxlength="40" />',
  527
+        )
  528
+        self.assertHTMLEqual(
  529
+            str(form['slug']),
  530
+            '<input id="id_slug" type="text" name="slug" maxlength="20" />',
  531
+        )
503 532
 
504  
-class TestWidgets(TestCase):
505  
-    def test_base_widgets(self):
506  
-        frm = TestWidgetForm()
  533
+    def test_label_overrides(self):
  534
+        form = FieldOverridesTroughFormMetaForm()
507 535
         self.assertHTMLEqual(
508  
-            str(frm['name']),
509  
-            '<textarea id="id_name" rows="10" cols="40" name="name"></textarea>'
  536
+            str(form['name'].label_tag()),
  537
+            '<label for="id_name">Title:</label>',
510 538
         )
511 539
         self.assertHTMLEqual(
512  
-            str(frm['url']),
513  
-            '<input id="id_url" type="text" class="url" name="url" maxlength="40" />'
  540
+            str(form['url'].label_tag()),
  541
+            '<label for="id_url">The URL:</label>',
514 542
         )
515 543
         self.assertHTMLEqual(
516  
-            str(frm['slug']),
517  
-            '<input id="id_slug" type="text" name="slug" maxlength="20" />'
  544
+            str(form['slug'].label_tag()),
  545
+            '<label for="id_slug">Slug:</label>',
518 546
         )
519 547
 
  548
+    def test_help_text_overrides(self):
  549
+        form = FieldOverridesTroughFormMetaForm()
  550
+        self.assertEqual(
  551
+            form['slug'].help_text,
  552
+            'Watch out! Letters, numbers, underscores and hyphens only.',
  553
+        )
  554
+
  555
+    def test_error_messages_overrides(self):
  556
+        form = FieldOverridesTroughFormMetaForm(data={
  557
+            'name': 'Category',
  558
+            'url': '/category/',
  559
+            'slug': '!%#*@',
  560
+        })
  561
+        form.full_clean()
  562
+
  563
+        error = [
  564
+            "Didn't you read the help text? "
  565
+            "We said letters, numbers, underscores and hyphens only!",
  566
+        ]
  567
+        self.assertEqual(form.errors, {'slug': error})
  568
+
520 569
 
521 570
 class IncompleteCategoryFormWithFields(forms.ModelForm):
522 571
     """
52  tests/model_formsets/tests.py
@@ -1261,7 +1261,7 @@ def test_prevent_duplicates_from_with_the_same_formset(self):
1261 1261
             ['Please correct the duplicate data for subtitle which must be unique for the month in posted.'])
1262 1262
 
1263 1263
 
1264  
-class TestModelFormsetWidgets(TestCase):
  1264
+class TestModelFormsetOverridesTroughFormMeta(TestCase):
1265 1265
     def test_modelformset_factory_widgets(self):
1266 1266
         widgets = {
1267 1267
             'name': forms.TextInput(attrs={'class': 'poet'})
@@ -1283,3 +1283,53 @@ def test_inlineformset_factory_widgets(self):
1283 1283
             "%s" % form['title'],
1284 1284
             '<input class="book" id="id_title" maxlength="100" name="title" type="text" />'
1285 1285
         )
  1286
+
  1287
+    def test_modelformset_factory_labels_overrides(self):
  1288
+        BookFormSet = modelformset_factory(Book, fields="__all__", labels={
  1289
+            'title': 'Name'
  1290
+        })
  1291
+        form = BookFormSet.form()
  1292
+        self.assertHTMLEqual(form['title'].label_tag(), '<label for="id_title">Name:</label>')
  1293
+
  1294
+    def test_inlineformset_factory_labels_overrides(self):
  1295
+        BookFormSet = inlineformset_factory(Author, Book, fields="__all__", labels={
  1296
+            'title': 'Name'
  1297
+        })
  1298
+        form = BookFormSet.form()
  1299
+        self.assertHTMLEqual(form['title'].label_tag(), '<label for="id_title">Name:</label>')
  1300
+
  1301
+    def test_modelformset_factory_help_text_overrides(self):
  1302
+        BookFormSet = modelformset_factory(Book, fields="__all__", help_texts={
  1303
+            'title': 'Choose carefully.'
  1304
+        })
  1305
+        form = BookFormSet.form()
  1306
+        self.assertEqual(form['title'].help_text, 'Choose carefully.')
  1307
+
  1308
+    def test_inlineformset_factory_help_text_overrides(self):
  1309
+        BookFormSet = inlineformset_factory(Author, Book, fields="__all__", help_texts={
  1310
+            'title': 'Choose carefully.'
  1311
+        })
  1312
+        form = BookFormSet.form()
  1313
+        self.assertEqual(form['title'].help_text, 'Choose carefully.')
  1314
+
  1315
+    def test_modelformset_factory_error_messages_overrides(self):
  1316
+        author = Author.objects.create(pk=1, name='Charles Baudelaire')
  1317
+        BookFormSet = modelformset_factory(Book, fields="__all__", error_messages={
  1318
+            'title': {
  1319
+                'max_length': 'Title too long!!'
  1320
+            }
  1321
+        })
  1322
+        form = BookFormSet.form(data={'title': 'Foo ' * 30, 'author': author.id})
  1323
+        form.full_clean()
  1324
+        self.assertEqual(form.errors, {'title': ['Title too long!!']})
  1325
+
  1326
+    def test_inlineformset_factory_error_messages_overrides(self):
  1327
+        author = Author.objects.create(pk=1, name='Charles Baudelaire')
  1328
+        BookFormSet = inlineformset_factory(Author, Book, fields="__all__", error_messages={
  1329
+            'title': {
  1330
+                'max_length': 'Title too long!!'
  1331
+            }
  1332
+        })
  1333
+        form = BookFormSet.form(data={'title': 'Foo ' * 30, 'author': author.id})
  1334
+        form.full_clean()
  1335
+        self.assertEqual(form.errors, {'title': ['Title too long!!']})

1 note on commit 9e50833

Jacob Valenta

Thank you so much, just ran into the need to do this.

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