Generic views implement the common CRUD patterns so your code only describes what's different.
Class-based views (CBVs) are classes whose as_view() produces a view function: path("", PostListView.as_view(), name="list").
Django's generic views cover common pages:
TemplateView: render a templateListView: a list of objects with pagination (paginate_by = 20); context hasobject_list,post_listandpage_objDetailView: one object bypkorslugfrom the URL; 404 if missingCreateView,UpdateView: a ModelForm; on success redirect tosuccess_urlor the object'sget_absolute_url()DeleteView: confirm on GET, delete on POSTFormView,RedirectView
Default templates follow app/model_suffix.html, such as blog/post_list.html, blog/post_detail.html and blog/post_form.html.
Customize by setting attributes or overriding methods:
get_queryset(): restrict the objects, for example only the user's ownget_context_data(**kwargs): add extra context; callsuper()firstform_valid(form): act before saving, such as setting the author
Behaviors come from mixins: LoginRequiredMixin, PermissionRequiredMixin, UserPassesTestMixin. Put them leftmost in the bases so their dispatch runs first.
Use reverse_lazy for success_url class attributes, since URLs aren't loaded when the class body runs.
CBVs shine for standard CRUD; for unusual flows, a function view is often clearer.
Example
# blog/views.py
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
from django.views.generic import CreateView, DeleteView, DetailView, ListView
from .models import Post
class PostListView(ListView):
model = Post
paginate_by = 20 # template: blog/post_list.html
def get_queryset(self):
return Post.objects.published().select_related("author")
class PostDetailView(DetailView):
model = Post # URL: <slug:slug>/ -> lookup by slug
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ["title", "slug", "body"] # template: blog/post_form.html
def form_valid(self, form):
form.instance.author = self.request.user.author
return super().form_valid(form)
class PostDeleteView(LoginRequiredMixin, DeleteView):
model = Post
success_url = reverse_lazy("blog:list")
def get_queryset(self): # only your own posts
return Post.objects.filter(author__user=self.request.user)Remember
- ListView/DetailView/CreateView/UpdateView/DeleteView cover CRUD
- Override get_queryset, get_context_data and form_valid to customize
- Mixins like LoginRequiredMixin go leftmost
- Use reverse_lazy for class-level URLs
Watch out for
- Putting LoginRequiredMixin after the generic view in the bases, so the check doesn't run first.