Web Development met Django: Complete Gids
Bouw moderne web applicaties met Django. Leer alles over models, views, templates en deployment.
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 %}
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
{% for category in categories %}
-
{{ category.name }}
{% endfor %}
{% 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!