Inleiding tot Django

Django is een high-level Python web framework dat snelle ontwikkeling en clean, pragmatisch design aanmoedigt. Het volgt de "batteries included" filosofie en biedt alles wat je nodig hebt om complexe, database-gedreven websites te bouwen. Grote bedrijven zoals Instagram, Mozilla, en National Geographic gebruiken Django.

Waarom Django Kiezen?

Django biedt vele voordelen voor web development:

  • Rapid Development: Snel van idee naar werkende applicatie
  • Security: Ingebouwde bescherming tegen veelvoorkomende aanvallen
  • Scalability: Kan groeien van kleine site tot enterprise-niveau
  • Versatility: Geschikt voor allerlei soorten web applicaties
  • DRY Principle: Don't Repeat Yourself
  • MVT Architecture: Model-View-Template patroon

Django Installatie en Setup

Laten we beginnen met een nieuwe Django project:

Virtual Environment

# Virtual environment aanmaken
python -m venv django_env

# Activeren (Windows)
django_env\Scripts\activate

# Activeren (macOS/Linux)
source django_env/bin/activate

Django Installeren

# Django installeren
pip install django

# Versie controleren
django-admin --version

Project Aanmaken

# Nieuw project starten
django-admin startproject mijnwebsite

# Naar project directory
cd mijnwebsite

# Development server starten
python manage.py runserver

Je website is nu bereikbaar op http://127.0.0.1:8000/

Django Project Structuur

Een Django project heeft de volgende structuur:

mijnwebsite/
    manage.py
    mijnwebsite/
        __init__.py
        settings.py      # Project instellingen
        urls.py          # URL routing
        wsgi.py          # WSGI configuratie
        asgi.py          # ASGI configuratie

Apps en Models

Django gebruikt apps om functionaliteit te organiseren. Laten we een blog app maken:

App Aanmaken

# Nieuwe app aanmaken
python manage.py startapp blog

Models Definiëren

Models definiëren je database structuur:

# blog/models.py
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse

class Category(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField(unique=True)
    description = models.TextField(blank=True)
    
    class Meta:
        verbose_name_plural = "Categories"
    
    def __str__(self):
        return self.name

class Post(models.Model):
    STATUS_CHOICES = [
        ('draft', 'Draft'),
        ('published', 'Published'),
    ]
    
    title = models.CharField(max_length=200)
    slug = models.SlugField(unique=True)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    content = models.TextField()
    excerpt = models.TextField(max_length=300, blank=True)
    status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        ordering = ['-created_at']
    
    def __str__(self):
        return self.title
    
    def get_absolute_url(self):
        return reverse('blog:post_detail', kwargs={'slug': self.slug})

Database Migraties

# App registreren in settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog',  # Nieuwe app toevoegen
]

# Migraties aanmaken
python manage.py makemigrations

# Migraties uitvoeren
python manage.py migrate

Views en URL Routing

Views bevatten de business logic van je applicatie:

Function-Based Views

# blog/views.py
from django.shortcuts import render, get_object_or_404
from django.core.paginator import Paginator
from .models import Post, Category

def post_list(request):
    posts = Post.objects.filter(status='published')
    
    # Paginatie
    paginator = Paginator(posts, 6)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    
    context = {
        'page_obj': page_obj,
        'posts': page_obj,
    }
    return render(request, 'blog/post_list.html', context)

def post_detail(request, slug):
    post = get_object_or_404(Post, slug=slug, status='published')
    
    # Gerelateerde posts
    related_posts = Post.objects.filter(
        category=post.category,
        status='published'
    ).exclude(id=post.id)[:3]
    
    context = {
        'post': post,
        'related_posts': related_posts,
    }
    return render(request, 'blog/post_detail.html', context)

def category_posts(request, slug):
    category = get_object_or_404(Category, slug=slug)
    posts = Post.objects.filter(category=category, status='published')
    
    context = {
        'category': category,
        'posts': posts,
    }
    return render(request, 'blog/category_posts.html', context)

Class-Based Views

# Alternative: Class-based views
from django.views.generic import ListView, DetailView

class PostListView(ListView):
    model = Post
    template_name = 'blog/post_list.html'
    context_object_name = 'posts'
    paginate_by = 6
    
    def get_queryset(self):
        return Post.objects.filter(status='published')

class PostDetailView(DetailView):
    model = Post
    template_name = 'blog/post_detail.html'
    context_object_name = 'post'
    
    def get_queryset(self):
        return Post.objects.filter(status='published')

URL Configuratie

# blog/urls.py
from django.urls import path
from . import views

app_name = 'blog'

urlpatterns = [
    path('', views.post_list, name='post_list'),
    path('post//', views.post_detail, name='post_detail'),
    path('category//', views.category_posts, name='category_posts'),
]

# mijnwebsite/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('blog/', include('blog.urls')),
    path('', include('blog.urls')),  # Blog als homepage
]

Templates en Static Files

Django gebruikt een krachtig template systeem:

Base Template





    
    
    {% block title %}Mijn Blog{% endblock %}
    {% load static %}
    
    


    
    
    
{% block content %} {% endblock %}

© 2024 Mijn Blog. Alle rechten voorbehouden.

Post List Template


{% extends 'base.html' %}

{% block title %}Blog Posts{% endblock %}

{% block content %}

Laatste Blog Posts

{% for post in posts %}

{{ post.title }}

Door {{ post.author.username }} op {{ post.created_at|date:"d M Y" }} in {{ post.category.name }}

{{ post.excerpt }}

Lees meer
{% empty %}

Geen posts gevonden.

{% endfor %} {% if page_obj.has_other_pages %} {% endif %}

Categorieën

{% endblock %}

Admin Interface

Django's admin interface is een van de krachtigste features:

Superuser Aanmaken

python manage.py createsuperuser

Models Registreren

# blog/admin.py
from django.contrib import admin
from .models import Post, Category

@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
    list_display = ['name', 'slug']
    prepopulated_fields = {'slug': ('name',)}

@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display = ['title', 'author', 'category', 'status', 'created_at']
    list_filter = ['status', 'category', 'created_at']
    search_fields = ['title', 'content']
    prepopulated_fields = {'slug': ('title',)}
    date_hierarchy = 'created_at'
    ordering = ['-created_at']
    
    fieldsets = (
        (None, {
            'fields': ('title', 'slug', 'author', 'category')
        }),
        ('Content', {
            'fields': ('content', 'excerpt')
        }),
        ('Status', {
            'fields': ('status',)
        }),
    )

Forms en User Input

Django forms helpen bij het valideren en verwerken van user input:

Contact Form

# blog/forms.py
from django import forms
from django.core.mail import send_mail

class ContactForm(forms.Form):
    naam = forms.CharField(max_length=100)
    email = forms.EmailField()
    onderwerp = forms.CharField(max_length=200)
    bericht = forms.CharField(widget=forms.Textarea)
    
    def send_email(self):
        send_mail(
            subject=self.cleaned_data['onderwerp'],
            message=self.cleaned_data['bericht'],
            from_email=self.cleaned_data['email'],
            recipient_list=['[email protected]'],
        )

# blog/views.py
from django.contrib import messages
from django.shortcuts import redirect
from .forms import ContactForm

def contact_view(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            form.send_email()
            messages.success(request, 'Uw bericht is verzonden!')
            return redirect('blog:contact')
    else:
        form = ContactForm()
    
    return render(request, 'blog/contact.html', {'form': form})

Static Files en Media

Configuratie voor CSS, JavaScript en uploads:

# settings.py
import os

# Static files (CSS, JavaScript, Images)
STATIC_URL = '/static/'
STATICFILES_DIRS = [
    BASE_DIR / "static",
]
STATIC_ROOT = BASE_DIR / "staticfiles"

# Media files (User uploads)
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / "media"

# urls.py
from django.conf import settings
from django.conf.urls.static import static

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Database Optimalisatie

Prestaties verbeteren met query optimalisatie:

# Inefficiënt (N+1 problem)
posts = Post.objects.all()
for post in posts:
    print(post.author.username)  # Database query per post

# Efficiënt (select_related)
posts = Post.objects.select_related('author', 'category').all()
for post in posts:
    print(post.author.username)  # Geen extra queries

# Voor many-to-many relaties
posts = Post.objects.prefetch_related('tags').all()

Security Best Practices

Django heeft ingebouwde security features:

# settings.py voor productie
DEBUG = False
ALLOWED_HOSTS = ['yourdomain.com']

# CSRF bescherming (standaard ingeschakeld)
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',  # CSRF
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

# Security headers
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'

# HTTPS (voor productie)
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 31536000

Testing

Django maakt testen eenvoudig:

# blog/tests.py
from django.test import TestCase, Client
from django.contrib.auth.models import User
from django.urls import reverse
from .models import Post, Category

class PostModelTest(TestCase):
    def setUp(self):
        self.user = User.objects.create_user(
            username='testuser',
            password='testpass123'
        )
        self.category = Category.objects.create(
            name='Test Category',
            slug='test-category'
        )
        self.post = Post.objects.create(
            title='Test Post',
            slug='test-post',
            author=self.user,
            category=self.category,
            content='Test content',
            status='published'
        )
    
    def test_post_creation(self):
        self.assertEqual(self.post.title, 'Test Post')
        self.assertEqual(str(self.post), 'Test Post')
    
    def test_post_absolute_url(self):
        self.assertEqual(
            self.post.get_absolute_url(),
            '/post/test-post/'
        )

class PostViewTest(TestCase):
    def setUp(self):
        self.client = Client()
        self.user = User.objects.create_user(
            username='testuser',
            password='testpass123'
        )
        self.category = Category.objects.create(
            name='Test Category',
            slug='test-category'
        )
        self.post = Post.objects.create(
            title='Test Post',
            slug='test-post',
            author=self.user,
            category=self.category,
            content='Test content',
            status='published'
        )
    
    def test_post_list_view(self):
        response = self.client.get(reverse('blog:post_list'))
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'Test Post')
    
    def test_post_detail_view(self):
        response = self.client.get(
            reverse('blog:post_detail', kwargs={'slug': 'test-post'})
        )
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'Test Post')

# Tests uitvoeren
python manage.py test

Deployment

Je Django app klaarmaken voor productie:

Requirements.txt

Django==4.2.7
gunicorn==21.2.0
psycopg2-binary==2.9.9
whitenoise==6.6.0

Environment Variables

# .env bestand
SECRET_KEY=your-secret-key-here
DEBUG=False
DATABASE_URL=postgres://user:pass@localhost/dbname
ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com

# settings.py
import os
from decouple import config

SECRET_KEY = config('SECRET_KEY')
DEBUG = config('DEBUG', default=False, cast=bool)
ALLOWED_HOSTS = config('ALLOWED_HOSTS').split(',')

Static Files voor Productie

# WhiteNoise voor static files
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',  # Toevoegen
    # ... andere middleware
]

# Collectstatic uitvoeren
python manage.py collectstatic

Best Practices

  • Keep it simple: Begin klein en bouw uit wanneer nodig
  • Use virtual environments: Isoleer je project dependencies
  • Follow PEP 8: Python coding standards
  • Write tests: Test-driven development waar mogelijk
  • Use migrations: Nooit handmatig database schema wijzigen
  • Secure by default: Gebruik Django's security features
  • Monitor performance: Django Debug Toolbar voor development

Volgende Stappen

Nu je de basics van Django kent, kun je:

  • REST APIs bouwen met Django REST framework
  • Real-time features toevoegen met Django Channels
  • Celery gebruiken voor background tasks
  • Caching implementeren met Redis
  • GraphQL APIs maken met Graphene-Django
  • Microservices architectuur verkennen

Conclusie

Django is een krachtig framework dat je helpt om snel en veilig web applicaties te bouwen. Met zijn "batteries included" aanpak krijg je veel functionaliteit out-of-the-box, terwijl je toch de flexibiliteit hebt om complexe, aangepaste oplossingen te bouwen.

Of je nu een eenvoudige blog of een complexe enterprise applicatie bouwt, Django biedt de tools en structuur die je nodig hebt. De grote community en uitgebreide documentatie maken het een uitstekende keuze voor web development met Python.

Wil je Django web development onder de knie krijgen? Bekijk onze Web Development cursus of neem contact met ons op voor meer informatie!