Intro to class-based generic views in Django

by George Brocklehurst (@georgebrock)

I work for thoughtbot

Presented at Django Stockholm Meetup Group,

Generic what-based who?

A function-based view

from django.template.response import TemplateResponse


def homepage_view(request):
    return TemplateResponse("homepage.html")
 

A class-based view

from django.template.response import TemplateResponse
from django.views.generic import View

class HomepageView(View):
    def get(self, request):
        return TemplateResponse("homepage.html")

There are View sublcasses that cover common cases, like rendering a template. If we use those instead we can simplify things.

A better class-based view

 
from django.views.generic import TemplateView

class HomepageView(TemplateView):
    template_name = "homepage.html"
 

Examples of other View subclasses

class BlogPostListView(ListView):
    model = BlogPost

class BlogPostDetailView(DetailView):
    model = BlogPost

class BlogPostCreateView(CreateView):
    model = BlogPost

class BlogPostUpdateView(UpdateView):
    model = BlogPost

class BlogPostDeleteView(DeleteView):
    model = BlogPost
    success_url = reverse_lazy("blog_post_list")

# ... and there are more!

Why is this better?

The View class is smarter than it looks

from django.template.response import TemplateResponse
from django.views.decorators.http import require_safe

@require_safe
def homepage_view(request):
    return TemplateResponse("homepage.html")

GET vs. POST

Classes over functions

Convention over configuration

Conventions are encoded in subclasses of View

Decisions, decisions
class BlogPostDetailView(View):
    def get(self, request, *args, **kwargs):
        return TemplateResponse(
            "blog/blogpost_detail.html",
            context={
                "blogpost": self.get_object(),
            },
        )

    def get_object(self):
        return get_object_or_404(
            BlogPost,
            pk=self.kwargs.get("pk"),
        )
Using Django's DetailView
class BlogPostDetailView(DetailView):
    model = BlogPost
 
 
 
 
 
 
 
 
 
 
 
 

But my app is unconventional!

Override conventions with attributes
class BlogPostDetailView(DetailView):
    model = BlogPost
    queryset = BlogPost.objects.filter(published=True)
 
 
Override conventions with methods
class BlogPostDetailView(DetailView):
    model = BlogPost
 
    def get_queryset(self):
        return BlogPost.objects.filter(published=True)

The Template Method pattern

Example: The SingleObject mixin

get_object() is the template method

How do I know what to override?

Use class-based views!

Questions?

Ask now, or later: @georgebrock on Twitter or email george@thoughtbot.com

I work for thoughtbot

These slides: http://georgebrock.github.com/talks/intro-to-class-based-generic-views