Django Class based views Form and object creation


Writing a view to create object can be quite boring. You have to display a form, you have to validate it, you have to save the item or return the form with an error. Unless you use one of the generic editing views.


from django.core.urlresolvers import reverse_lazy
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from .models import Pokemon

class PokemonCreate(CreateView):
    model = Pokemon
    fields = ['name', 'species']

class PokemonUpdate(UpdateView):
    model = Pokemon
    fields = ['name', 'species']

class PokemonDelete(DeleteView):
    model = Pokemon
    success_url = reverse_lazy('pokedex')

CreateView and UpdateView have two required attribute, model and fields. By default, both use a template name based on the model name suffixed by '_form'. You can change only the suffix with the attribute template_name_suffix. The DeleteView show a confirmation message before deleting the object.

Both UpdateView and DeleteView need to fetch on object. They use the same method as DetailView, extracting variable from the url and matching the object fields.

app/templates/app/pokemon_form.html (extract)

<form action="" method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Save" />

form contains the form with all needed fields. Here, it will be displayed with a paragraph for each field because of as_p.

app/templates/app/pokemon_confirm_delete.html (extract)

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

The csrf_token tag is required because of django protection against request forgery. The attribute action is left empty as the url displaying the form is the same as the one handling the deletion/save.

Two issues remain with the model, if using the same as with the list and detail exemple. First, create and update will complain about a missing redirection url. That can be solved by adding a get_absolute_url to the pokemon model. Second issue is the deletion confirmation not displaying meaningful information. To solve this, the easiest solution is to add a string representation.


from django.db import models
from django.urls import reverse
from django.utils.encoding import python_2_unicode_compatible

class Pokemon(models.Model):
    name = models.CharField(max_length=24)
    species = models.CharField(max_length=48)

    def get_absolute_url(self):
        return reverse('app:pokemon', kwargs={'pk'})

    def __str__(self):

The class decorator will make sure everything work smoothly under python 2.