In het vorige artikel hebben we gekeken naar waarom klasse-gebaseerde weergaven (CBV) in Django nodig zijn en welke voordelen ze hebben in vergelijking met functie-gebaseerde weergaven (FBV). In deze post gaan we dieper in op de basis weergaveklasse van Django, die als fundament voor alle CBV's kan worden beschouwd.

"Om CBV goed te begrijpen, is het belangrijk om te begrijpen hoe django.views.View werkt en welke structuur het heeft."


1. Wat is een Django View klasse?

Alle klasse-gebaseerde weergaven in Django zijn gebaseerd op de django.views.View klasse en worden als volgt geërfd:

from django.views import View

class MyView(View):
    def get(self, request, *args, **kwargs):
        # Logica voor het verwerken van een GET-verzoek
        ...

    def post(self, request, *args, **kwargs):
        # Logica voor het verwerken van een POST-verzoek
        ...

Kenmerken van de View klasse

  1. Scheiding van methoden per HTTP-methode
    Wanneer een verzoek binnenkomt, roept Django intern automatisch de functie aan die overeenkomt met de verzoekmethode via de dispatch() methode, zoals get(), post(), put(), delete().

    • Het gebruik van een voorwaarde zoals "if request.method == 'GET': … else: …" zoals bij FBV is niet nodig, zodat de code structuur schoner is.
  2. Overerving en uitbreidbaarheid
    Door de View klasse te erven, kunnen meerdere kindweergaven worden gemaakt, waarbij gemeenschappelijke logica in de bovenliggende klasse en specifieke logica in de kindklasse worden geplaatst, wat de herbruikbaarheid van code maximaliseert.


2. Basisstructuur en principes van de View klasse

Django View structuur LEGO-stijl

Het eenvoudigste voorbeeld

# views.py
from django.http import HttpResponse
from django.views import View

class HelloCBV(View):
    def get(self, request, *args, **kwargs):
        return HttpResponse("Hallo, CBV!")
  • get()-methode: Deze wordt uitgevoerd wanneer er een GET-verzoek (bijvoorbeeld via de URL of een link) wordt verzonden vanuit de browser.

  • HttpResponse("Hallo, CBV!"): Dit maakt en retourneert een tekstvormig antwoord.

urls.py verbinden

# urls.py
from django.urls import path
from .views import HelloCBV

urlpatterns = [
    path('hello/', HelloCBV.as_view(), name='hello_cbv'),
]
  • .as_view() methode transformeert de CBV naar een formaat dat Django kan begrijpen.

  • Wanneer het URL-patroon is verbonden, wordt de get() methode van HelloCBV aangeroepen wanneer er een GET-verzoek binnenkomt op http://example.com/hello/.


3. Gebruik en praktische voorbeelden van de View klasse

Het is zeldzaam dat we alleen een “string teruggeven” zoals in het bovenstaande voorbeeld. Vaak in echte projecten worden JSON-antwoorden, template-rendering, of databasetaken uitgevoerd. Hier bekijken we JSON-antwoorden en template-rendering als voorbeelden.

3.1 Voorbeeld van JSON-antwoorden

# views.py
from django.http import JsonResponse
from django.views import View

class UserDataView(View):
    def get(self, request, *args, **kwargs):
        # Bijvoorbeeld: Stel dat we een user_id als GET-parameter ontvangen
        user_id = request.GET.get('user_id', None)
        if not user_id:
            return JsonResponse({'error': 'Geen user_id opgegeven'}, status=400)

        # In werkelijkheid voeren we een DB-query uit
        user_data = {
            'id': user_id,
            'name': f'User_{user_id}',
            'role': 'admin'
        }
        return JsonResponse(user_data, status=200)

    def post(self, request, *args, **kwargs):
        # We kunnen JSON of formgegevens parseren uit het POST-verzoeklichaam.
        # request.POST, request.body, request.FILES kunnen worden gebruikt
        # In een echte service kan er een logica voor JSON-parsing en DB-opslag worden toegevoegd
        new_user_data = {
            'id': 123,
            'name': 'NewUser',
            'role': 'member'
        }
        return JsonResponse(new_user_data, status=201)
  • JsonResponse: Dit is een handige tool in Django om JSON-antwoorden te genereren.

  • request.GET, request.POST: Hiermee kunnen GET-/POST-parameters uit het HttpRequest-object in Django worden gehaald.

  • In de praktijk worden DB-modellen gekoppeld of serializers gebruikt om gegevens op een meer gestructureerde manier te verwerken.

3.2 Voorbeeld van template-rendering

# views.py
from django.shortcuts import render
from django.views import View

class GreetingView(View):
    def get(self, request, *args, **kwargs):
        context = {
            'title': 'Welkom op mijn site',
            'greeting': 'Hallo, dit is een GreetingView!'
        }
        return render(request, 'greeting.html', context)
<!-- templates/greeting.html -->
<!DOCTYPE html>
<html>
<head>
  <title>{{ title }}</title>
</head>
<body>
  <h1>{{ greeting }}</h1>
</body>
</html>
  • render() functie zoekt het templatebestand (greeting.html) en retourneert de gerenderde HTML als een HttpResponse.

  • Zo kan de template-rendering eenvoudig binnen de CBV worden gedaan.


4. Uitbreiding en herbruikbaarheid van de View klasse

Een van de grootste redenen waarom de View klasse nuttig is, is “code herbruikbaarheid”. Naarmate projecten groter worden, is het veel efficiënter om gemeenschappelijke logica (bijvoorbeeld logging, autorisatie, verwerking van gemeenschappelijke gegevens) in de bovenliggende klasse te plaatsen en in de kindklassen te gebruiken.

4.1 Gemeenschappelijke logica in de bovenliggende klasse

# views.py
from django.http import JsonResponse
from django.views import View

class BaseLoggingView(View):
    def dispatch(self, request, *args, **kwargs):
        # Voer gemeenschappelijke logica uit voor alle verzoeken (GET/POST etc.)
        print(f"[Log] {request.method} verzoek op {request.path}")
        return super().dispatch(request, *args, **kwargs)

class ChildLoggingView(BaseLoggingView):
    def get(self, request, *args, **kwargs):
        data = {'message': 'GET antwoord van kind'}
        return JsonResponse(data)

    def post(self, request, *args, **kwargs):
        data = {'message': 'POST antwoord van kind'}
        return JsonResponse(data)
  • dispatch() methode: Dit is de kernmethode waarmee je de uitvoering van de viewlogica vóór en na het aanroepen kunt beheersen.

  • In dit voorbeeld worden logs voor alle verzoeken vastgelegd en vervolgens wordt super().dispatch() gebruikt om de daadwerkelijke get(), post(), enz. aan te roepen.

4.2 Functie toevoeging via Mixin

In Django wordt vaak de techniek Mixin gebruikt om “specifieke functies alleen in te voegen”. Bijvoorbeeld, LoginRequiredMixin (voor het controleren van inlogstatus) en PermissionRequiredMixin (voor het controleren van rechten) worden in de CBV gebruikt.

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import View
from django.http import JsonResponse

class SecuredView(LoginRequiredMixin, View):
    def get(self, request, *args, **kwargs):
        return JsonResponse({'message': 'Je bent geauthenticeerd.'})
  • Mixin wordt verder behandeld in latere artikelen over generieke weergaven en machtigingsbeheer, dus het is voldoende om te weten dat functies op deze manier kunnen worden gecombineerd.

5. Eenvoudige vergelijking met FBV

Categorie FBV (functie-gebaseerde weergave) CBV (klasse-gebaseerde weergave)
Schrijfvorm In functie-vorm geschreven In klasse & methode-vorm geschreven
HTTP-methode verwerking if request.method == 'GET': ... else: ... get(), post() afzonderlijk gescheiden
Kans op code duplicatie Complexe logica kan leiden tot duplicerende code Herbruikbare gemeenschappelijke logica via overerving en mixins
Uitbreidbaarheid Gemeenschappelijke logica zit vaak vermengd in de functie Geschikt voor complexe vereisten via een klasse-erfstructuur
Leesbaarheid Voordelig voor eenvoudige prototypes Geschikt voor een duidelijke structuur naarmate de omvang toeneemt
  • FBV is snel te schrijven voor kleine of eenvoudige functies, terwijl CBV voordelig is voor uitbreidbaarheid en onderhoud.

  • Met name bij teamprojecten of middelgrote tot grote projecten is het efficiënt om CBV te gebruiken.


6. Dieper ingaan: dispatch() en URL-parameters

Django View verzoek flowchart

6.1 Redenen om dispatch() direct te overschrijven

  • Gemeenschappelijke pre- en post-processing: Hier kunnen logica zoals het controleren van databaseverbindingen of autorisatiecontroles worden uitgevoerd telkens wanneer er een verzoek binnenkomt.

  • Methode-mapping: Intern wordt request.method.lower() gebruikt om get(), post(), put() te vinden en aan te roepen. Als je bijvoorbeeld aanvullende methoden zoals PATCH op een aangepaste manier wilt afhandelen, kan je dispatch() overschrijven.

class CustomDispatchView(View):
    def dispatch(self, request, *args, **kwargs):
        print("Aangepaste pre-processing logica hier.")
        response = super().dispatch(request, *args, **kwargs)
        print("Aangepaste post-processing logica hier.")
        return response

6.2 URL-parameters ontvangen

Als je in urls.py een padparameter zoals <int:user_id>/ specificeert, kunnen de waarden in de get() en post() methoden van de CBV ontvangen worden via kwargs.

![Django View structuur LEGO-stijl](/media/whitedec/blog_img/view_class_lego_structure.webp)# urls.py
urlpatterns = [
    path('user/<int:user_id>/', UserDetailView.as_view(), name='user_detail'),
]

# views.py
class UserDetailView(View):
    def get(self, request, *args, **kwargs):
        user_id = kwargs.get('user_id')
        # Voer een DB-query uit op user_id
        return HttpResponse(f"User ID: {user_id}")
  • Net als bij FBV kunnen URL-parameters uit kwargs worden gehaald.

7. Een rijker praktisch voorbeeld: eenvoudige forumvoorbeeld

Voor degenen die graag de View klasse iets praktischer willen gebruiken, laten we een eenvoudig voorbeeld bekijken van het maken van een lijst met berichten en een detailpagina. (In de volgende post zullen we generieke weergaven behandelen, wat het eenvoudiger maakt om CRUD te implementeren, maar hier laten we zien dat het ook mogelijk is met de basis View klasse.)

# models.py - voorbeeldmodel
from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title
# views.py
from django.views import View
from django.shortcuts import render, get_object_or_404
from .models import Post

# Berichtlijst
class PostListView(View):
    def get(self, request, *args, **kwargs):
        posts = Post.objects.order_by('-created_at')
        context = {'posts': posts}
        return render(request, 'post_list.html', context)

# Berichtdetail
class PostDetailView(View):
    def get(self, request, *args, **kwargs):
        post_id = kwargs.get('pk')
        post = get_object_or_404(Post, pk=post_id)
        context = {'post': post}
        return render(request, 'post_detail.html', context)
<!-- post_list.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Berichtlijst</title>
</head>
<body>
    <h1>Berichtlijst</h1>
    <ul>
        {% for post in posts %}
            <li>
                <a href="{% url 'post_detail' post.id %}">{{ post.title }}</a>
            </li>
        {% endfor %}
    </ul>
</body>
</html>
<!-- post_detail.html -->
<!DOCTYPE html>
<html>
<head>
    <title>{{ post.title }}</title>
</head>
<body>
    <h1>{{ post.title }}</h1>
    <p>{{ post.content }}</p>
    <p>Datum van schrijven: {{ post.created_at }}</p>
</body>
</html>
# urls.py
from django.urls import path
from .views import PostListView, PostDetailView

urlpatterns = [
    path('posts/', PostListView.as_view(), name='post_list'),
    path('posts/<int:pk>/', PostDetailView.as_view(), name='post_detail'),
]
  • PostListView: Bij een GET-verzoek worden alle berichten opgehaald en doorgegeven aan het template (post_list.html).

  • PostDetailView: Een specifiek bericht wordt opgezocht op basis van de URL-parameter pk en doorgegeven aan het template (post_detail.html).

  • Zo kun je eenvoudig lijsten en detailpagina's samenstellen met alleen de basis View klasse.

Om echter de volledige CRUD functionaliteit te realiseren, zijn Create/Update/Delete logica's nodig. De generieke weergaven (Generic Views) die Django biedt, faciliteren dit proces en dat wordt in het volgende artikel uitgebreid behandeld!


8. Conclusie en aankondiging van de volgende post

Tot zover een uitleg van hoe de basis View klasse van Django werkt en hoe deze in de praktijk kan worden toegepast. Samenvattend zijn de belangrijkste punten:

  1. Door django.views.View te erven en methoden zoals get() / post() / dispatch() te overschrijven, reageer je op HTTP-verzoeken.

  2. Door gemeenschappelijke logica in de bovenliggende klasse te plaatsen en alleen de noodzakelijke delen in de kindweergaven te herschrijven, maximaliseer je de herbruikbaarheid van code.

  3. Je kunt eenvoudig viewlogica schrijven voor verschillende scenario's zoals template-rendering, JSON-antwoorden en DB-query's.

  4. Zoals het praktische voorbeeld met een eenvoudig forum laat zien, kun je met alleen de basis View klasse voldoende werkende projecten creëren.
    Echter, om CRUD-taken eenvoudiger te verwerken, is het leren van de generieke weergaven (Generic Views) die Django biedt, veel gemakkelijker.

In de volgende post zullen we ons concentreren op de FormView klasse, waarmee je het proces van “gebruikersinvoer opslaan, en bij validatiefouten foutmeldingen weergeven” kunt automatiseren.

De CBV-serie gaat door!

  • Deel 3: “FormView voor eenvoudige formulierverwerking”
  • Deel 4: “ListView & DetailView gebruik”
  • Deel 5: “CreateView, UpdateView, DeleteView voor CRUD implementatie”
  • … (en verder)

Bekijk het vorige artikel


Extra referentiemateriaal

Ik hoop dat dit artikel een deel van je vragen over de structuur en toepassing van de basis View klasse heeft beantwoord. In de volgende post leren we hoe we het proces van “formulier invullen → valideren → foutafhandeling → redirect naar succes” eenvoudiger kunnen verwerken via de FormView, dus houd alsjeblieft de aandacht erbij!


“De View klasse van Django is niet alleen een manier om de code per HTTP-methode te scheiden, maar het is een krachtig hulpmiddel dat de uitbreidbaarheid en het onderhoud van grootschalige projecten revolutionair kan verbeteren.”

Laten we samen verder exploreren in CBV en productieve Django-ontwikkeling realiseren!