Custom errors in forms

Hi, I’m trying to make a custom error in a form in a class based view (CreateView). I have read the documentation and it is supposed that with the “clean()” function you can add errors, but my problem is that the form is submitted even when the error should appear.

this is my class:

class RecommendationCreateView(LoginRequiredMixin, CreateView):
    model = Recommendation
    template_name = 'recommendation/recommendation_new.html'
    form_class = NewPostForm
    success_url = reverse_lazy('home')


    def get_form_kwargs(self):
        """ Passes the request object to the form class.
         This is necessary to only display members that belong to a given user"""

        kwargs = super(RecommendationCreateView, self).get_form_kwargs()
        kwargs['request'] = self.request.user
        return kwargs


    def post(self, request):
        super(RecommendationCreateView, self).post(request)
        to_user=request.POST['to_user']
        to_user = user_model.objects.filter(id = to_user).get()
        hobby = request.POST['hobby']
        hobby = Hobby.objects.filter(id = hobby).get()
        recom = Recommendation.objects.create(from_user=request.user, to_user=to_user, hobby=hobby, text=request.POST['text'])
        recom.save()

        return redirect('recommendations')

this is my form:

class NewPostForm(forms.ModelForm):

    def clean(self):
        super(NewPostForm, self).clean()
        to_user          = self.cleaned_data.get('to_user')    

        to_user = user_model.objects.filter(username=to_user.username).get()
        
        if to_user.username == 'NAME':
            self._errors['to_user'] = 'Custom error to display'
        return self.cleaned_data

    class Meta:
        model = Recommendation
        fields = ('from_user', 'to_user', 'hobby', 'text')
        widgets = {'from_user': forms.HiddenInput()}

this is my model:

class Recommendation(models.Model):
    
    id = models.UUIDField(
        primary_key = True,
        default = uuid.uuid4,
        editable = False
    )
    from_user = models.ForeignKey(
        get_user_model(),
        on_delete=models.CASCADE,
        related_name="recommendation_request_sent",
    )
    to_user = models.ForeignKey(
        get_user_model(),
        on_delete=models.CASCADE,
        related_name="recommendation_requests_received",
    )
    hobby = models.ForeignKey(Hobby, on_delete=models.CASCADE)
    text = models.TextField(null = True, blank = True)

    def get_absolute_url(self):
        return reverse('recommendations')

My goal is that when I make a recommendation if I send the form with the field “to_user” with the name “NAME” I get a custom error in the form. I enter the function “clean” and enters the if when they are the same but the form is sent anyway.

How can I stop the form from being sent? I have tried other functions like “form_valid()” but it never enters this function.

Let’s make sure we’re clear on terminology here.

All of this work is done on the server. The only way that any of these tests are performed are in the server after the form has been submitted to the server.

So I’m not clear what you mean by saying " the form is sent anyway". The form must be submitted before any of this work takes place.

yes, when I click on send, the form is sent and all this is executed.

What I want is that when the field “to_user” is sent with the value “NAME” when I submit the form, the server checks for errors and if it doesn’t have any it creates one.

But my problem is that when I send the value “NAME” the field “to_user” the server does not execute the error showing in the form but it ignores it and this way the form is sent and the object is created.

I want the server to return a custom error for that field and the object is not created when I click on send.

Ok, your next step then is to review the Working with forms docs along with the Forms API to see how you’re supposed to bind the form to the data submitted from the browser.

You want to review your post method to see how it’s not interacting with the form in the way you’ll see in the docs and the tutorials.