Form handling with class-based views

    • Initial GET (blank or prepopulated form)
    • POST with invalid data (typically redisplay form with errors)
    • POST with valid data (process the data and typically redirect)
      Implementing this yourself often results in a lot of repeated boilerplate code(see Using a form in a view). To help avoidthis, Django provides a collection of generic class-based views for formprocessing.

    Given a simple contact form:

    forms.py

    The view can be constructed using a :

    views.py

    1. from myapp.forms import ContactForm
    2. from django.views.generic.edit import FormView
    3.  
    4. class ContactView(FormView):
    5. template_name = 'contact.html'
    6. form_class = ContactForm
    7. success_url = '/thanks/'
    8.  
    9. def form_valid(self, form):
    10. # This method is called when valid form data has been POSTed.
    11. # It should return an HttpResponse.
    12. form.send_email()
    13. return super().form_valid(form)

    注意:

    Generic views really shine when working with models. These genericviews will automatically create a , so long asthey can work out which model class to use:

    • If the model attribute isgiven, that model class will be used.
    • If returns an object, the class of that object will be used.
    • If a queryset isgiven, the model for that queryset will be used.
      Model form views provide a implementationthat saves the model automatically. You can override this if you have anyspecial requirements; see below for examples.

    You don't even need to provide a success_url forCreateView or - they will useget_absolute_url() on the model object if available.

    If you want to use a custom (for instance toadd extra validation) simply setform_class on your view.

    注解

    First we need to add to ourAuthor class:

    models.py

    Then we can use and friends to do the actualwork. Notice how we're just configuring the generic class-based viewshere; we don't have to write any logic ourselves:

    views.py

    1. from django.urls import reverse_lazy
    2. from myapp.models import Author
    3.  
    4. class AuthorCreate(CreateView):
    5. model = Author
    6. fields = ['name']
    7.  
    8. class AuthorUpdate(UpdateView):
    9. model = Author
    10. fields = ['name']
    11.  
    12. class AuthorDelete(DeleteView):
    13. model = Author
    14. success_url = reverse_lazy('author-list')

    注解

    We have to use here, not justreverse() as the urls are not loaded when the file is imported.

    The fields attribute works the same way as the fields attribute on theinner Meta class on ModelForm. Unless you define theform class in another way, the attribute is required and the view will raisean exception if it's not.

    If you specify both the fieldsand attributes, anImproperlyConfigured exception will be raised.

    Finally, we hook these new views into the URLconf:

    注解

    These views inheritwhich usesto construct thebased on the model.

    In this example:

    To track the user that created an object using a ,you can use a custom ModelForm to do this. First, addthe foreign key relation to the model:

    models.py

    1. from django.contrib.auth.models import User
    2. from django.db import models
    3.  
    4. class Author(models.Model):
    5. name = models.CharField(max_length=200)
    6. created_by = models.ForeignKey(User, on_delete=models.CASCADE)
    7.  
    8. # ...

    In the view, ensure that you don't include created_by in the list of fieldsto edit, and overrideform_valid() to add the user:

    views.py

    LoginRequiredMixin prevents users whoaren't logged in from accessing the form. If you omit that, you'll need tohandle unauthorized users in .

    Here is a simple example showing how you might go about implementing a form thatworks for AJAX requests as well as 'normal' form POSTs:

    1. from django.http import JsonResponse
    2. from django.views.generic.edit import CreateView
    3. from myapp.models import Author
    4. class AjaxableResponseMixin:
    5. """
    6. Mixin to add AJAX support to a form.
    7. Must be used with an object-based FormView (e.g. CreateView)
    8. """
    9. def form_invalid(self, form):
    10. response = super().form_invalid(form)
    11. if self.request.is_ajax():
    12. return JsonResponse(form.errors, status=400)
    13. else:
    14. return response
    15.  
    16. def form_valid(self, form):
    17. # We make sure to call the parent's form_valid() method because
    18. # it might do some processing (in the case of CreateView, it will
    19. # call form.save() for example).
    20. response = super().form_valid(form)
    21. if self.request.is_ajax():
    22. data = {
    23. 'pk': self.object.pk,
    24. }
    25. return JsonResponse(data)
    26. else:
    27. return response
    28.  
    29. class AuthorCreate(AjaxableResponseMixin, CreateView):
    30. fields = ['name']