Search code examples
djangodjango-class-based-viewsconfirmationdjango-validation

Django class-based DeleteView robust confirmation?


I'm using Django 1.10.6 and I'm using a class-based view DeleteView.

Example myapp/views.py:

from django.views.generic.edit import DeleteView
from django.urls import reverse_lazy
from myapp.models import Author

class AuthorDelete(DeleteView):
    model = Author
    success_url = reverse_lazy('author-list')

Example myapp/author_confirm_delete.html:

<form action="" method="post">{% csrf_token %}
    <p>Are you sure you want to delete "{{ object }}"?</p>
    <input type="submit" value="Confirm" />
</form>

Because deleting is a serious operation, I want to add more robust confirmation such that the user needs to type the author name in before the author can be deleted (and it must match. similar to the github confirmation for deleting repositories). I guess this might be implemented as some kind of form validation.

What's the django-way to add this type of confirmation?


Solution

  • I would create a Django ModelForm, it could then compare a separate HTML input field to the model instance field. In the view, if the form validation fails... the delete doesn't happen.

    # myapp/forms.py
    
    from django import forms
    
    class ConfirmDeleteForm(forms.ModelForm):
        confirm = forms.CharField(label='Confirm your name', max_length=100)
    
        class Meta:
            model = Author
            fields = []
    
        def clean(self):
            confirm = super().clean().get('confirm')
    
            if self.instance.name.lower() != confirm.lower():
                raise forms.ValidationError('Confirmation incorrect')
    

     

    # myapp/views.py
    
    from django.views.generic.edit import DeleteView
    from django.urls import reverse_lazy
    from myapp.models import Author
    from myapp.forms import ConfirmDeleteForm
    
    class AuthorDelete(DeleteView):
        model = Author
        success_url = reverse_lazy('author-list')
    
        def get_context_data(self, **kwargs):
            """
            Overridden to add a confirmation form to the context.
            """
            context = super().get_context_data(**kwargs)
    
            if 'form' not in kwargs:
                context['form'] = ConfirmDeleteForm()
    
            return context
    
        def post(self, request, *args, **kwargs):
            """
            Overridden to process the confirmation form before deleting
            the object.
            """
            self.object = self.get_object()
            form = ConfirmDeleteForm(request.POST, instance=self.object)
    
            if form.is_valid():
                return self.delete(request, *args, **kwargs)
            else:
                return self.render_to_response(
                    self.get_context_data(form=form),
                )
    

     

    <!-- myapp/author_confirm_delete.html -->
    
    <form method="post">
        {% csrf_token %}
        <p>Are you sure you want to delete "{{ object }}"?</p>
        {{ form }}
        <input type="submit" value="Confirm" />
    </form>