Skip to main content

Processing Forms and Data Entry

Generic editing views provide a structured way to handle form display, validation, and object persistence. These views automate the repetitive tasks of instantiating forms, checking for validity, and redirecting on success.

Handling Basic Forms

To process a standard Django form that is not tied to a specific model, use FormView. You must provide a form_class, a template_name, and a success_url.

from django.urls import reverse_lazy
from django.views import generic
from .forms import ContactForm

class ContactView(generic.FormView):
form_class = ContactForm
success_url = reverse_lazy("authors_list")
template_name = "generic_views/form.html"

In this pattern:

  • GET requests render the template_name with an empty instance of form_class.
  • POST requests validate the form. If valid, the view redirects to success_url. If invalid, it re-renders the template with the form containing error messages.

Creating Model Instances

CreateView simplifies the process of creating and saving new model instances. It automatically generates a ModelForm for the specified model.

from django.views import generic
from .models import Author

class AuthorCreate(generic.CreateView):
model = Author
fields = ["name", "email"]
success_url = "/list/authors/"

When using CreateView (and UpdateView), you must either specify fields to let Django generate the form or provide a custom form_class. Using both will result in an ImproperlyConfigured error.

Updating Existing Instances

UpdateView works similarly to CreateView but operates on an existing object retrieved via a URL parameter (usually pk or slug).

from django.views import generic
from .models import Author

class AuthorUpdate(generic.UpdateView):
model = Author
fields = "__all__"
success_url = "/list/authors/"

By default, UpdateView uses a template named <model_name>_form.html. You can customize this by setting template_name_suffix.

Deleting Instances

DeleteView handles the deletion of an object. A GET request typically displays a confirmation page, while a POST request performs the deletion.

from django.views import generic
from .models import Author

class AuthorDelete(generic.DeleteView):
model = Author
success_url = "/list/authors/"

The default template for DeleteView is <model_name>_confirm_delete.html.

Customizing Form Initialization

If your form requires additional data from the request (such as the current user), override get_form_kwargs. This is a common pattern in django.contrib.auth.views.

# Example from django/contrib/auth/views.py
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["request"] = self.request
return kwargs

This passes the request object into the form's __init__ method, allowing the form to perform logic based on the current user or session.

Performing Actions on Success

To execute custom logic after a form is successfully validated but before redirecting, override form_valid. This is useful for sending emails, logging users in, or updating related models.

# Example based on django/contrib/auth/views.py
def form_valid(self, form):
# Perform custom logic, like saving the form or sending a notification
form.save()
# You can also perform actions like logging in a user
# auth_login(self.request, form.get_user())
return super().form_valid(form)

Troubleshooting and Gotchas

Missing Success URL

If you do not provide a success_url in a CreateView or UpdateView, Django will attempt to call get_absolute_url() on the object being saved. If neither is available, an ImproperlyConfigured error is raised.

Fields vs Form Class

For security reasons, CreateView and UpdateView require either the fields attribute or a form_class.

  • Do not use fields = "__all__" in production if you want to exclude sensitive fields.
  • Do not define both fields and form_class; choose one.

Delete Confirmation

DeleteView expects a POST request to actually delete the object. If you attempt to delete via a GET request, the object will not be removed; instead, the confirmation template will be rendered.

Dynamic Redirects

If your success_url needs to include the ID of the newly created or updated object, override get_success_url:

from django.urls import reverse

def get_success_url(self):
return reverse("author_detail", args=[self.object.id])