CodeOath
← All posts
Python70 min total · 18 parts

Django Fundamentals: MVT Architecture, the ORM, and Middleware

Contents — Part 9 of 18: Views: Function-Based vs. Class-Based
Part 9 of 18 · ~1 min

Views: Function-Based vs. Class-Based

# Function-based — explicit, reads top to bottom
def order_list(request):
    orders = Order.objects.select_related("customer").all()
    return render(request, "orders/list.html", {"orders": orders})

def order_create(request):
    if request.method == "POST":
        form = OrderForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect("order-list")
    else:
        form = OrderForm()
    return render(request, "orders/form.html", {"form": form})
# Class-based — less code for standard CRUD patterns
class OrderListView(ListView):
    model = Order
    template_name = "orders/list.html"
    paginate_by = 20

    def get_queryset(self):
        return Order.objects.select_related("customer").filter(status="pending")

class OrderCreateView(CreateView):
    model = Order
    form_class = OrderForm
    success_url = reverse_lazy("order-list")

Class-based views trade explicitness for convention — a ListView gives you pagination, queryset filtering hooks, and template context for free, at the cost of needing to know Django's conventions (which method to override, what context variable name it uses by default) to see what's actually happening. A practical rule of thumb: standard CRUD (list, detail, create, update, delete) is usually less code as a class-based generic view; a view with genuinely custom logic that doesn't map cleanly onto "list of X" or "form for X" is often clearer as a plain function.

get_context_data — the standard CBV extension point

class OrderListView(ListView):
    model = Order

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)   # always call super() first
        context["pending_count"] = Order.objects.filter(status="pending").count()
        return context

Forgetting super().get_context_data(**kwargs) is a common CBV mistake — it's what actually populates the base context (object_list, pagination info) that the template expects; overwriting it entirely breaks the built-in template rendering.