59

I can see how to add an error message to a field when using forms, but what about model form?

This is my test model:

class Author(models.Model):
    first_name = models.CharField(max_length=125)
    last_name = models.CharField(max_length=125)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

My model form:

class AuthorForm(forms.ModelForm):
    class Meta:
        model = Author

The error message on the fields: first_name and last_name is:

This field is required

How do I change that in a model form?

Milo
  • 3,365
  • 9
  • 30
  • 44
iJK
  • 4,655
  • 12
  • 63
  • 95

7 Answers7

58

For simple cases, you can specify custom error messages

class AuthorForm(forms.ModelForm):
    first_name = forms.CharField(error_messages={'required': 'Please let us know what to call you!'})
    class Meta:
        model = Author
davelupt
  • 1,845
  • 4
  • 21
  • 32
chefsmart
  • 6,873
  • 9
  • 42
  • 47
  • 1
    Cool thanks. I did not know what would be the result of doing that. The documentation says "Declared fields will override the default ones generated by using the model attribute" so I should be good. I would also have to set the max_field again on the model form field. – iJK Aug 09 '10 at 04:04
  • 21
    Is it really necessary to repeat field declarations in the form? How about the DRY principle django is proud of? – paweloque Jan 27 '11 at 12:18
  • LOL, man, I think OP want use forms from models but not declare forms two times. – Denis Jan 24 '13 at 10:33
  • 1
    I think that with respect to the client side, being explicit is more important then DRY. – gabn88 Jul 21 '15 at 17:23
57

New in Django 1.6:

ModelForm accepts several new Meta options.

  • Fields included in the localized_fields list will be localized (by setting localize on the form field).
  • The labels, help_texts and error_messages options may be used to customize the default fields, see Overriding the default fields for details.

From that:

class AuthorForm(ModelForm):
    class Meta:
        model = Author
        fields = ('name', 'title', 'birth_date')
        labels = {
            'name': _('Writer'),
        }
        help_texts = {
            'name': _('Some useful help text.'),
        }
        error_messages = {
            'name': {
                'max_length': _("This writer's name is too long."),
            },
        }

Related: Django's ModelForm - where is the list of Meta options?

Community
  • 1
  • 1
doctaphred
  • 2,504
  • 1
  • 23
  • 26
  • i don't understand the _() surrounding the custom error message text, so i took that out. but this is the first snippet that worked for me. i'm on django 1.6. thank you, sir! – Eric S. Mar 06 '14 at 17:00
  • 4
    You're welcome! If you're curious, the underscore function is a common shortcut for an internationalization utility: http://stackoverflow.com/questions/2964244/django-meaning-of-leading-underscore-in-list-of-tuples-used-to-define-choice-fi – doctaphred Mar 06 '14 at 18:31
  • I think this should be the accepted answer as it follow DRY principles. When using ModelForm, there shouldn't be a need to declare fields again and there shouldn't be a need to override methods either. – mrchestnut Feb 01 '19 at 23:31
  • The defaults in the Meta class are only used if the fields and widgets are not defined deliberately. If they are defined deliberately, the error messages should be defined there, or in the `__init__` method. – Uri Aug 10 '19 at 08:31
  • https://stackoverflow.com/questions/57424228/custom-error-messages-not-working-in-django-modelform – Uri Aug 10 '19 at 08:35
  • "Fields defined declaratively are left as-is, therefore any customizations made to Meta attributes such as widgets, labels, help_texts, or error_messages are ignored; these only apply to fields that are generated automatically." - from https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#modelforms-overriding-default-fields – Uri Aug 10 '19 at 08:38
21

Another easy way of doing this is just override it in init.

class AuthorForm(forms.ModelForm):
    class Meta:
        model = Author

    def __init__(self, *args, **kwargs):
        super(AuthorForm, self).__init__(*args, **kwargs)

        # add custom error messages
        self.fields['name'].error_messages.update({
            'required': 'Please let us know what to call you!',
        })
slajma
  • 1,609
  • 15
  • 17
jamesmfriedman
  • 623
  • 6
  • 6
  • 1
    This is much better solution than all other in this thread because 1) You don't have to use any extensions 2) you don't have to rewrite whole form field definition because it depends on definition of model field. +1 – Vladimir Prudnikov Jan 07 '14 at 08:54
  • 4
    One note thought, you have to use it like this `self.fields['name'].error_messages['required'] = 'Please let us know what to call you!'` or using `.update()` method, otherwise you reset all other error messages. – Vladimir Prudnikov Jan 07 '14 at 12:11
15

I have wondered about this many times as well. That's why I finally wrote a small extension to the ModelForm class, which allows me to set arbitrary field attributes - including the error messages - via the Meta class. The code and explanation can be found here: http://blog.brendel.com/2012/01/django-modelforms-setting-any-field.html

You will be able to do things like this:

class AuthorForm(ExtendedMetaModelForm):
    class Meta:
        model = Author
        field_args = {
            "first_name" : {
                "error_messages" : {
                    "required" : "Please let us know what to call you!"
                }
            }
        }

I think that's what you are looking for, right?

jbrendel
  • 2,390
  • 3
  • 18
  • 18
  • This is a great way to do this. Certainly more DRY than redefining form fields. – suda Mar 09 '12 at 12:23
  • @suda you aren't really redefining, you are overriding the default behavior based on the model associated. similar to changing an input to a textarea, you are overriding the default. – Chris Feb 19 '13 at 18:02
7

the easyest way is to override the clean method:

class AuthorForm(forms.ModelForm):
   class Meta:
      model = Author
   def clean(self):
      if self.cleaned_data.get('name')=="":
         raise forms.ValidationError('No name!')
      return self.cleaned_data
Mermoz
  • 14,898
  • 17
  • 60
  • 85
5

I have a cleaner solution, based on jamesmfriedman's answer. This solution is even more DRY, especially if you have lots of fields.

custom_errors = {
    'required': 'Your custom error message'
}

class AuthorForm(forms.ModelForm):
    class Meta:
        model = Author

    def __init__(self, *args, **kwargs):
        super(AuthorForm, self).__init__(*args, **kwargs)

        for field in self.fields:
            self.fields[field].error_messages = custom_errors
Vingtoft
  • 13,368
  • 23
  • 86
  • 135
3

You can easily check and put custom error message by overriding clean()method and using self.add_error(field, message):

def clean(self):
    super(PromotionForm, self).clean()
    error_message = ''
    field = ''
    # reusable check
    if self.cleaned_data['reusable'] == 0:
        error_message = 'reusable should not be zero'
        field = 'reusable'
        self.add_error(field, error_message)
        raise ValidationError(error_message)

    return self.cleaned_data
Moe Far
  • 2,742
  • 2
  • 23
  • 41