Search code examples
pythondjangoformsmaterialize

CBV pass CBV form with validation


I'm new to django.

I'm building a CRUD app using Class-based views as follow:

views.py

class CreateInterventionView(CreateView):
    form_class = NewIntervention
    success_url = reverse_lazy('list')
    template_name = 'intervention_create.html'

    def form_valid(self, form):
       form.instance.speaker = self.request.user
       return super().form_valid(form)

class UpdateInterventionView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
    model = Intervention
    form_class = NewIntervention
    success_url = reverse_lazy('list')
    template_name = 'intervention_update.html'

    def form_valid(self, form):
        form.instance.speaker = self.request.user
        return super().form_valid(form)

    def test_func(self):
        post = self.get_object()
        if self.request.user == post.speaker:
           return True
        return False

class DeleteInterventionView(DeleteView):
    model = Intervention
    template_name = 'intervention_delete.html'
    context_object = 'intervention'
    success_url = reverse_lazy('list')

forms.py

class NewIntervention(forms.ModelForm):

class Meta:
    model = Intervention
    fields = ('subject', 'begin_date', 'end_date', 'description', 'campus')
    widgets = {
        'description': forms.Textarea(attrs={'class': 'materialize-textarea'}),
        'begin_date': forms.DateInput(attrs={'class': 'datepicker'}),
        'end_date': forms.DateInput(attrs={'class': 'datepicker'}),
        }

def clean(self):
    cleaned_data = super().clean()
    begin_date = cleaned_data.get("begin_date")
    end_date = cleaned_data.get("end_date")
    if end_date < begin_date:
        raise forms.ValidationError("End date should be greater than start date.")

my html modal

    <!-- Modal Trigger -->
  <a class="waves-effect waves-light btn modal-trigger" href="#modal1">Modal</a>
  <!-- Modal Structure -->
  <div id="modal1" class="modal">
    <div class="modal-content">
      <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <button class="btn modal-close waves-effect waves-light" type="submit" name="action">Submit
          <i class="material-icons right">send</i>
        </button>
      </form>   
     </div>
  </div>

I also have a CBV ListView and i want the user to be able to create/update/delete interventions in same page as ListView (i have buttons for crud operations and when the user click on it it open a materializecss modal with the form)

I tried this:

class ListInterventionView(ListView):
    model = Intervention
    template_name = 'intervention_list.html'
    ordering = ''
    paginate_by = 5

    def get_queryset(self):
        return Intervention.objects.filter(speaker=self.request.user)

    def get_context_data(self, **kwargs):
        context = super(ListInterventionView, self).get_context_data(**kwargs)
        context['form'] = CreateInterventionView.form_class
        return context

The modal is working and i have my form inside it but when i create new intervention it's not working and i don't know how to do the validation in my listview.

Any advice is welcome. Thanks a lot.

Best regards.


Solution

  • The problem here is that you are not returning the cleaned_data in your clean method:

    class NewIntervention(forms.ModelForm):
        # ...
        def clean(self):
            cleaned_data = super().clean()
            begin_date = cleaned_data.get("begin_date")
            end_date = cleaned_data.get("end_date")
            if end_date < begin_date:
                raise forms.ValidationError("End date should be greater than start date.")
            return cleaned_data
    

    Edit

    You also need to connect the action attribute of your form to the appropriate url; So let's say you have the following url for creating a new Intervention instance:

    ...
    path('intervention/new/', CreateInterventionView.as_view(), name='new-intervention'),
    ...
    

    Then you need to change your form's action as:

        <!-- Modal Trigger -->
      <a class="waves-effect waves-light btn modal-trigger" href="#modal1">Modal</a>
      <!-- Modal Structure -->
      <div id="modal1" class="modal">
        <div class="modal-content">
          <form method="post" action="{% url 'new-intervention' %}">
            {% csrf_token %}
            {{ form.as_p }}
            <button class="btn modal-close waves-effect waves-light" type="submit" name="action">Submit
              <i class="material-icons right">send</i>
            </button>
          </form>   
         </div>
      </div>