darko
darko

Reputation: 2458

displaying errors with django ModelForm

I am having trouble figuring out how to control field validation for ModelForms.

Here is my Model Form:

class UserForm(ModelForm):
    class Meta:
        model = User
        fields = ('email', 'password')

Here is how I am rendering my form in the template:

<form method="post" action="">
    {% csrf_token %}
    {{ userform.as_p }}
    <input type="submit" value="Submit" />
</form>

Here is my view:

def login_page(request):
    if request.method == 'POST':
        userform = UserForm(request.POST)
        if userform.is_valid():
            email = request.POST['email']
            password = request.POST['password']
            user = authenticate(username=email, password=password)
            if user is not None:
                login(request, user)
                return redirect('/dashboard/')
            else:
                # How can I give the user feedback about authentication failute here. Right now it just reloads the form without any messages.
                return render(request, "login.html", {"userform": userform}) 
        else:
            # Because .is_valid() is called, The userform will validate for email addresses and that a password input is present here.
            return render(request, "login.html", {"userform": userform}) 
    else:
        userform = UserForm()
        return render(request, "login.html", {"userform": userform})

From reading the docs, this seems like it should be as simple as passing my form some custom attribute; but since I am working with a ModelForm, I am unsure whether this is achieved in the same way.

Could anyone provide an example or tips on how best to control ModelForm field errors?

Thanks!

Upvotes: 5

Views: 5683

Answers (3)

securecurve
securecurve

Reputation: 5807

Very easy, you have multiple ways to display the error messages:

First one:

1- Override the clean method inside your form/modelform:

def clean(self):
    # To keep the main validation and error messages
    super(your_form_name, self).clean()

    # Now it's time to add your custom validation
    if len(self.cleaned_data['password']) < 10:
         self._errors['password']='your password\'s length is too short'
         # you may also use the below line to custom your error message, but it doesn't work with me for some reason
         raise forms.ValidationError('Your password is too short')

Second One

By using django built in validators.

You can use the validators inside the models with the custom error message you want like this:

RE = re.compile('^[0-9]{10}$')

field_name = models.CharField('Name', default='your_name',validators=[RegexValidator(regex=RE, message="Inapproperiate Name!")],)

where validators can utilize multiple built-in validation rules that you can validate against.

please refer to this django documentation

also you can use validators inside your forms definition, but the error message inside validators will not work as it did with models in case of errors, to custom error message use the below third method.

Third Method:

skill = forms.CharField(
    label = 'SSkill', 
    min_length = 2,
    max_length = 12, 
    # message kwarg is only usable in models, yet,
    #it doesn't spawn error here.
    #validators=[RegexValidator(regex=NME, message="In-approperiate number!")], 
    required = True,
    #Errors dictionary 
    error_messages={'required': 'Please enter your skill','min_length':'very short entry','invalid':'Improper format'}, 
    #Similar to default you pass in model
    initial = 'Extreme Coder'
) 

Where, requied, min_length, max_length, along with others, are all fomr kw arguments, where the invalid will only be selected when validators a couple of lines above didn't match the criteria you selected inside validators.

Fourth Method

In this method, you will override your modelform's definition like this:

def __init__(self, *args, **kwargs):
    super(Your_Form, self).__init__(*args, **kwargs)
    self.fields['password'].error_messages['required'] = 'I require that you fill out this field'

Fifth Method:

I have seen some nice way to custom errors in one of the stackoverflow posts like this:

class Meta:
    model = Customer 
    exclude = ('user',)
    fields = ['birthday','name'] 
    field_args = {
        "name" : {
            "error_messages" : {
                "required" : "Please let us know what to call you!"
                "max_length" : "Too short!!!"
            }           
        }
    }

reference to fifth method is: Brendel's Blog

May be there are other/better ways of doing things, but those are the most common, at least to me :-)

I hope this post helps.

Upvotes: 3

Alasdair
Alasdair

Reputation: 308769

The Django authentication app has a built in AuthenticationForm that you use. If you look at the source code, you can see their approach is to check the username and password inside the clean method. That way, a validation error can be raised if the username and password combination is invalid, and the form will display the error.

You can import the AuthenticationForm and use it in your login view with the following import:

from django.contrib.auth.forms import Authentication

You may also be able to use the built in login view as well. This means you can take advantage of the added functionality, such as displaying a message if the user does not have cookies enabled. It also decreases the chance of you creating a security vulnerability.

Upvotes: 1

Timmy O&#39;Mahony
Timmy O&#39;Mahony

Reputation: 53971

If you want to return error or warning messages back to the user (even if there are no errors in the validated form) you can either use the messaging framework, or you can insert custom error messsages into the form.

I think the messaging framework is your best bet - I don't think it's a good idea to inject errors into the form. If someone has entered a wrong username and pword, it's not a validation error, so it shouldn't be treated as such. A validation error should only be thrown if the wrong type of data is entered to a field, not the incorrect value.

Upvotes: 1

Related Questions