I'm trying to raise forms.validation error under a specific circumstance with a field (using class based views)

I think there’s possibly a way around this with javascript, but my knowledge is very poor on that.

I’m making a function in my form class which examines a condition between two values and returns ValidationError if one value is less than the other. In other words - if the number input on the form is less than the number on that field in the first database record, then the validation error message should show (on the update page).

In my form class I have this function:

  def clean(self):

        db_first_record = DashboardModel.objects.first()
        form_number = self.cleaned_data.get('the_number')
      
        if(db_first_record.the_number <= form_number):
            pass
        else:
            raise forms.ValidationError("Not allowed")

then I’m trying to override the Post method in the UpdateView class, the reason why I’m overriding post is because I’m also allowing the user to update Images (uploaded from an ImageField)

I’m trying to call this form function before form.save() happens, but it isn’t really working and I don’t know where to go.

    if form.is_valid():
          #  form.clean()
            f = form.save(commit=False)
            f.user = request.user
            f.save()

The is_valid method calls the clean method.
See Form and field validation | Django documentation | Django.

What specifically is not working?

It would be helpful if you posted the complete view.

I’m getting this ValueError:

ValueError: The view dashboard.views.view didn’t return an HttpResponse object. It returned None instead.

but I don’t get this if I completely remove the clean method, I made sure the view is working correctly before trying this field validation action (and the numbers also print correctly inside clean(), it’s just that when I use this forms.ValidationError in the code - everything bombs)

here is the view (ignore the very experimental image update code):

class RecordUpdatePage(StaffMemberRequiredMixin, LoginRequiredMixin , UpdateView):
    
    model = DashboardModel
    template_name = "dashboard/record_update.html"
    form_class = RecordForm
    success_url = reverse_lazy("dashboard")
    context_object_name = 'record'


    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['imageform'] = ImageForm
            
        return context


    def post(self, request, *args, **kwargs):
        form_class = self.get_form_class()
        form = self.get_form(form_class)

        pk = self.get_object().id
        d = DashboardModel.objects.get(id=pk)

        files = request.FILES.getlist('image')


        if form.is_valid():
            f = form.save(commit=False)
            f.user = request.user
            f.save()

            if(d.image_set.all()): #if images are present in the record  
                for i in files:
                    Image.objects.update_or_create(project=f, image=i)    
                #d.image_set.all().delete() #using Django Cleanup, no need to do this
            else:
                for i in files:
                    Image.objects.create(project=f, image=i)   
            messages.success(request, "New images updated")

            return self.form_valid(form)
        else:
            print(form.errors)


    def get_success_url(self):
        return reverse_lazy('record_detail', kwargs={'pk': self.object.pk})

All views must, under all conditions, return an HttpResponse object.

You have a chain of logic in your view where that doesn’t occur.

Ensure that under all conditions, your view returns a response.

I changed this as the return in Post:

response = HttpResponse()
response.content = self.form_valid(form)

    return response

but I’m still getting the same error now, I don’t know enough about HTTP to truly understand this error. It seemed like self.form_valid(form) was returning the response as I could successfully update records like this before overriding clean()

You changed what in the post? You’re showing some code but no context where it appears.

Note: The problem is in the view, not in your clean method. (At least not directly)

Once you fix your view, the reason why it’s failing should become apparent.

I meant I just changed the return (what’s highlighted). It’s guess work for me now, I’m close to giving up. I can only return a response from these View methods because it is the whole class which is the view.

  def post(self, request, *args, **kwargs):
        form_class = self.get_form_class()
        form = self.get_form(form_class)

	if form.is_valid():
            f = form.save(commit=False)
            f.user = request.user
            f.save()

            #return self.form_valid(form)
            response = HttpResponse()
            response.content = self.form_valid(form)

            return response

urls.py

 path('dashboard/record_update/<str:pk>/', RecordUpdatePage.as_view(),  name= 'record_update'),

Follow your logic where form.is_valid is False. What’s going to happen in your view?

Also, you should review Working with forms | Django documentation | Django. Even though it’s written for FBVs, the principles and logic is the same.

it will crash, but I couldn’t get a HttpResponseRedirect working either, I tried:
HttpResponseRedirect('/dashboard/') among other things

I am not a fan of this documentation, it isn’t helpful or clear and there is too much ambiguity

I can’t comment or offer assistance without you posting the code you’re trying to use. (And that means the complete view, not just a fragment.)

I appreciate the helping hand, give me a while and I will try to make sure I understand what I’m doing again because I’m starting to become blind to it

It is working with form_valid:

this is all I had to do:

        def form_valid(self,form):
            response = super().form_valid(form)

            return response

I was initially trying to make conditions within form_valid and that wasn’t working properly, but I didn’t realize at that point that this method only reflects on the POSTed data.

I still don’t get this to work by overriding def post and returning response in the same way (calling the superclass constructor)

edit… it’s working in post now:

I just had the return in the wrong place, can be easy to get confused by the tabbing

   def post(self, request, *args, **kwargs):
        response = super().post(self, request, *args, **kwargs)

        form_class = self.get_form_class()
        form = self.get_form(form_class)


        if form.is_valid():

            f = form.save(commit=False)
            f.user = request.user
            f.save()

            return self.form_valid(form)
        else:
            print(form.errors)

        return response

this part of the documentation is relevant:

https://docs.djangoproject.com/en/4.1/topics/class-based-views/generic-editing/