Waarom Django?
Django is een van de meest populaire Python web frameworks. Het volgt het "batteries included" principe, wat betekent dat het veel functionaliteit out-of-the-box biedt.
Voordelen van Django:
- Snelle ontwikkeling: Veel functionaliteit is al ingebouwd
- Veilig: Ingebouwde bescherming tegen veel voorkomende aanvallen
- Schaalbaar: Gebruikt door grote bedrijven zoals Instagram en Spotify
- DRY principe: Don't Repeat Yourself - minder code duplicatie
- Admin interface: Automatisch gegenereerde beheerinterface
Django Project Setup
Laten we beginnen met het opzetten van een nieuw Django project:
Installatie:
# Maak een virtuele omgeving
python -m venv myproject_env
# Activeer de virtuele omgeving
# Windows:
myproject_env\Scripts\activate
# macOS/Linux:
source myproject_env/bin/activate
# Installeer Django
pip install django
# Maak een nieuw project
django-admin startproject myproject
cd myproject
# Start de development server
python manage.py runserver
Django Project Structuur
Een typisch Django project heeft de volgende structuur:
myproject/
manage.py
myproject/
__init__.py
settings.py
urls.py
wsgi.py
asgi.py
Belangrijke bestanden:
- manage.py: Command-line utility voor het project
- settings.py: Project configuratie
- urls.py: URL routing
- wsgi.py: WSGI configuratie voor deployment
Je Eerste Django App
Django projecten bestaan uit apps. Elke app heeft een specifieke functionaliteit:
# Maak een nieuwe app
python manage.py startapp blog
# Voeg de app toe aan 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
]
Models: Database Structuur
Models definiëren je database structuur in Python code:
# blog/models.py
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
content = models.TextField()
category = models.ForeignKey(Category, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
published = models.BooleanField(default=False)
class Meta:
ordering = ['-created_at']
def __str__(self):
return self.title
Migrations:
# Maak migrations
python manage.py makemigrations
# Pas migrations toe
python manage.py migrate
# Maak een superuser
python manage.py createsuperuser
Views: Business Logic
Views bevatten de logica voor het verwerken van requests:
# blog/views.py
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView
from .models import Post, Category
class PostListView(ListView):
model = Post
queryset = Post.objects.filter(published=True)
template_name = 'blog/post_list.html'
context_object_name = 'posts'
paginate_by = 10
def post_detail(request, slug):
post = get_object_or_404(Post, slug=slug, published=True)
return render(request, 'blog/post_detail.html', {'post': post})
def category_posts(request, category_slug):
category = get_object_or_404(Category, slug=category_slug)
posts = Post.objects.filter(category=category, published=True)
return render(request, 'blog/category_posts.html', {
'category': category,
'posts': posts
})
Templates: Frontend
Templates definiëren hoe je data wordt weergegeven:
Base Template:
<!-- blog/templates/blog/base.html -->
<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Mijn Blog{% endblock %}</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="{% url 'blog:post_list' %}">Mijn Blog</a>
</div>
</nav>
<main class="container mt-4">
{% block content %}
{% endblock %}
</main>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
Post List Template:
<!-- blog/templates/blog/post_list.html -->
{% extends 'blog/base.html' %}
{% block title %}Blog Posts{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-8">
<h1>Laatste Blog Posts</h1>
{% for post in posts %}
<div class="card mb-4">
<div class="card-body">
<h5 class="card-title">
<a href="{% url 'blog:post_detail' post.slug %}">{{ post.title }}</a>
</h5>
<p class="card-text">{{ post.content|truncatewords:50 }}</p>
<small class="text-muted">
Door {{ post.author.username }} op {{ post.created_at|date:"d M Y" }}
</small>
</div>
</div>
{% empty %}
<p>Nog geen blog posts beschikbaar.</p>
{% endfor %}
<!-- Pagination -->
{% if is_paginated %}
<nav aria-label="Page navigation">
<ul class="pagination">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}">Vorige</a>
</li>
{% endif %}
<li class="page-item active">
<span class="page-link">{{ page_obj.number }}</span>
</li>
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}">Volgende</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>
</div>
{% endblock %}
URL Routing
URL patterns koppelen URLs aan views:
# blog/urls.py
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
path('', views.PostListView.as_view(), name='post_list'),
path('post/<slug:slug>/', views.post_detail, name='post_detail'),
path('category/<slug:category_slug>/', views.category_posts, name='category_posts'),
]
# myproject/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('blog/', include('blog.urls')),
]
Django Admin
Django biedt een automatisch gegenereerde admin interface:
# 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', 'published', 'created_at']
list_filter = ['published', 'created_at', 'category']
search_fields = ['title', 'content']
prepopulated_fields = {'slug': ('title',)}
date_hierarchy = 'created_at'
ordering = ['-created_at']
Forms en Validatie
Django forms maken het gemakkelijk om user input te verwerken:
# blog/forms.py
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'content', 'category', 'published']
widgets = {
'title': forms.TextInput(attrs={'class': 'form-control'}),
'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 10}),
'category': forms.Select(attrs={'class': 'form-select'}),
}
def clean_title(self):
title = self.cleaned_data['title']
if len(title) < 5:
raise forms.ValidationError("Titel moet minimaal 5 karakters lang zijn.")
return title
Testing
Django heeft uitgebreide testing ondersteuning:
# blog/tests.py
from django.test import TestCase
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='testpass'
)
self.category = Category.objects.create(
name='Test Category',
slug='test-category'
)
def test_post_creation(self):
post = Post.objects.create(
title='Test Post',
slug='test-post',
author=self.user,
content='Test content',
category=self.category,
published=True
)
self.assertEqual(post.title, 'Test Post')
self.assertTrue(post.published)
def test_post_str_representation(self):
post = Post.objects.create(
title='Test Post',
slug='test-post',
author=self.user,
content='Test content',
category=self.category
)
self.assertEqual(str(post), 'Test Post')
class PostViewTest(TestCase):
def setUp(self):
self.user = User.objects.create_user(
username='testuser',
password='testpass'
)
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,
content='Test content',
category=self.category,
published=True
)
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
Voor productie deployment zijn er verschillende opties:
Production Settings:
# settings/production.py
from .base import *
DEBUG = False
ALLOWED_HOSTS = ['jouwdomain.com', 'www.jouwdomain.com']
# Database
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'jouw_db_naam',
'USER': 'jouw_db_user',
'PASSWORD': 'jouw_db_password',
'HOST': 'localhost',
'PORT': '5432',
}
}
# Static files
STATIC_ROOT = '/var/www/jouwproject/static/'
MEDIA_ROOT = '/var/www/jouwproject/media/'
# Security
SECURE_SSL_REDIRECT = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
Requirements.txt:
Django==4.2.0
psycopg2-binary==2.9.5
gunicorn==20.1.0
whitenoise==6.4.0
Pillow==9.5.0
Best Practices
- Gebruik virtuele omgevingen: Isoleer project dependencies
- Splits settings: Verschillende settings voor development/production
- Gebruik environment variables: Voor gevoelige informatie
- Schrijf tests: Zorg voor betrouwbare code
- Gebruik migrations: Versie beheer voor database schema
- Cache implementeren: Voor betere performance
- Logging configureren: Voor debugging en monitoring
Conclusie
Django is een krachtig framework dat je helpt om snel professionele web applicaties te bouwen. Door zijn "batteries included" filosofie kun je je focussen op je applicatie logica in plaats van boilerplate code.
Belangrijke voordelen van Django:
- Snelle ontwikkeling met minder code
- Ingebouwde veiligheidsfeatures
- Schaalbaarheid voor grote applicaties
- Uitgebreide documentatie en community
- Flexibiliteit en uitbreidbaarheid
Wil je Django leren in een gestructureerde omgeving? Bekijk onze Django Web Development cursus voor praktijkgerichte training!