Django how to pass custom error message though context in class based views

I need to be show custom error message for invalid forms. I don’t know how to do it in class based views so I can show it to my html template. here is my class based views:

class EditPatient(UpdateView):
      model = Patient
      form_class = PatientUpdateFrom
      template_name = 'hospital/edit-patient.html'
      def form_valid(self, form):
        error_message = None
        if form.is_valid():
           name = self.request.POST["patient_name"]
           email = self.request.POST["phone"]
           if len(name) > 20:
               error_message = 'maximum 20 character allowed in name'
           if len(phone) > 20:
               error_message = 'maximum 15 character allowed in phone'
          
           """ #I tried this but didn't work 
           def get_context_data(self, **kwargs):
                context = super(EditPatient,self).get_context_data(**kwargs)
                context['error_message'] = error_message
                return context
           """
          
           if not error_message:
                messages.add_message(self.request, messages.INFO, 'Patient Sucessfully Updated')     
                form.save()
                 
           
           return redirect('hospital:edit-patient',self.object.slug)

You want to perform your tests in the form’s clean (or clean_<fieldname>) method, generating errors as documented at Form and field validation | Django documentation | Django.

Doing the validation in form_valid is beyond the point where this should be done. Form_valid is intended to be called after all validation is performed and assumes that the form at that point is good.

1 Like

KenWhitesell here I am actually updating few fields of my another model. So I can raise validation error for PatientUpdateFrom but how to show error message for custom fields which not related with PatientUpdateFrom where I am getting input for updating fields for another model.

Form validation is not tied to model fields. Form validation is done on the form fields.

I am not using form for few fields. Assume here I am getting input for name and email which belongs from another model and I am not using any form fields. see the below example:

if not error_message:

                messages.add_message(self.request, messages.INFO, 'Patient Sucessfully Updated')

                form.save()

                UserProfile.objects.filter(acess_patient_model=form.instance).update(name=name,email=email)

how to show my custom error message for name and email? In function based view normally I passed the context somethings like this:

if len(name) > 20:
               error_message = 'maximum 20 character allowed in name'

context{'error_message':error_message}

What does all that have to do with this?

if not error_message:

                messages.add_message(self.request, messages.INFO, 'Patient Sucessfully Updated')

                form.save()

                UserProfile.objects.filter(acess_patient_model=form.instance).update(name=name,email=email)

how to show my custom error message for name and email? In function based view normally I passed the context somethings like this:

if len(name) > 20:
               error_message = 'maximum 20 character allowed in name'

context{'error_message':error_message}

Ok, there’s too much information missing from talking in the abstract here. We’ll need to see the complete view at this point, along with the form involved.

The snippet you posted shows two data elements being pulled from the data being posted, which should be form fields, and therefore validated by the form. Quite frankly, if you’re doing it any other way, you’re not using the form and views as designed.

here is my full views:

class EditPatient(UpdateView):

      model = Patient

      form_class = PatientUpdateFrom

      template_name = 'hospital/edit-patient.html'

      def form_valid(self, form):

        error_message = None

        if form.is_valid():

           name = self.request.POST["patient_name"]

           email = self.request.POST['email']

           phone = self.request.POST['phone']

           gender = self.request.POST['gender']

           country = self.request.POST['country']

           state = self.request.POST['state']

           city = self.request.POST['city']

           zip_code = self.request.POST['zip_code']

           address = self.request.POST['address']

           birth_date = self.request.POST['date_of_birth']  

           date_time_obj = datetime.datetime.strptime(birth_date, "%Y-%m-%d")

           email = str(email)

           phone = str(phone)

           gender = str(gender)

           country = str(country)

           state = str(state)

           city = str(city)

           zip_code = str(zip_code)

           address = str(address)

           gender_choice = ['Male','Female','Other']

           if len(email) > 300:

               error_message = 'maximum 300 character allowed in email'

           if len(phone) > 20:

               error_message = 'maximum 20 character allowed in phone'

           if len(gender)>10:

                 error_message = 'maximum 10 character allowed in gender'

           if len(country)>100:

                 error_message = 'maximum 100 character allowed in country'

           if len(state)>100:

                 error_message = 'maximum 100 character allowed in state'

           if len(city)>100:

                 error_message = 'maximum 100 character allowed in city'

           if len(zip_code)>100:

                 error_message = 'maximum 100 character allowed in zip code'

           if len(address)>1000:

                 error_message = 'maximum 1000 character allowed in address'

           if gender not in gender_choice:

                 error_message = "please select gender"

           if phone == "":

               error_message = "please enter phone number"

           if email  == "":

               error_message = "please enter email"

           if date_time_obj > datetime.datetime.today():

               error_message = "Birth date can't be future"

                

           date_time_obj = date_time_obj.date()

           calculate_age = age(date_time_obj)  

           if not error_message:

                messages.add_message(self.request, messages.INFO, 'Patient Sucessfully Updated')

                form.save()

                UserProfile.objects.filter(acess_patient_model=form.instance).update(age=calculate_age,date_of_birth=date_time_obj,email=email,phone=phone,gender=gender,country=country,state=state,city=city,zip_code=zip_code,address=address)

                return redirect('hospital:patient-details',self.object.slug)

         

           return redirect('hospital:edit-patient',self.object.slug)

PatientUpdateFrom

class PatientUpdateFrom(forms.ModelForm):

     patient_name =  forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'}),required=True)

   

     class Meta:

         model = Patient

         fields = ['patient_name']

             

     def clean_patient_name(self):

         patient_name  = self.cleaned_data['patient_name']

         if len(patient_name) > 100:

            raise forms.ValidationError("Maximum 100 character allowed")

         return patient_name

How to render my error_message in my html template ?

These should all be fields in your form. (A ModelForm is not limited to only the fields in the model. You can add additional fields as necessary.) This allows you to do proper form validation and error-message handling.

Also, see the docs at: Working with forms | Django documentation | Django

1 Like

KenWhitesell Thanks for the explanation. I thought we can only validate models fields in ModelForm.

As you said ModelForm is not limited to only the fields in the model. But it’s only rising validation error only for for doctor_name which coming from my Doctor model. How to raise validation error for email which coming from another model?

class DoctorFrom(forms.ModelForm):
       class Meta:
         model = Doctor
         fields = ['doctor_name']

       def clean_doctor_name(self):

           doctor_name = self.cleaned_data['doctor_name']

           if len(doctor_name)>1:

               raise forms.ValidationError('maximum 100 character allowed')

           return doctor_name
       
       def clean_email(self):

           email = self.cleaned_data['email']

           if len(email)>3:

               raise forms.ValidationError('maximum 300 character allowed')

           return email

Data in a form is coming from the form. I have no idea what you mean by:

It’s coming from UserProfile Model. Should I add class Meta for UserProfile?

class DoctorFrom(forms.ModelForm):
       class Meta:
         model = Doctor
         fields = ['doctor_name']
       class Meta:
         model = UserProfile
         fields = ['email']

You can’t create two Meta classes in one form, nor can you create one Model Form from two different models.
If you’re going to use Model Forms for two different models, you need to create a Model Form for each model.

1 Like

KenWhitesell but it working and it’s rendering email fields in my html {{doctor_form.email}}

There’s too much information missing from your posts at this point. I know you’ve been making a lot of changes, and I can’t follow what’s going on from all the various snippets posted previously.

Please post the current and complete forms, views, models and templates involved with this process at the moment.

KenWhitesell I got your point. We need to be use separate Model Form for each model. Right now it’s difficult to explain my all model, views and forms. I got your point.