Python
Django Complete Guide
Master Django web development from setup to production deployment including models, views, templates, authentication, REST APIs, testing, performance optimisation, and enterprise-grade best practices.
What you'll learn
- Structure a Django project following best practices
- Design models with the Django ORM
- Build class-based views and REST APIs with DRF
- Implement Django authentication and permissions
- Write unit and integration tests with pytest-django
- Optimise database queries and cache with Redis
- Deploy Django to production with gunicorn and Nginx
Project Structure
Bash
1pip install django==5.0 djangorestframework psycopg2-binary
2django-admin startproject config .
3python manage.py startapp courses
4
5# Recommended layout
6myproject/
7├── config/ # settings, urls, wsgi, asgi
8├── courses/ # domain app
9│ ├── models.py
10│ ├── serializers.py
11│ ├── views.py
12│ ├── urls.py
13│ └── tests/
14├── users/
15├── requirements/
16│ ├── base.txt
17│ ├── development.txt
18│ └── production.txt
19└── manage.pyModels & ORM
Python
1# courses/models.py
2from django.db import models
3from django.contrib.auth import get_user_model
4
5User = get_user_model()
6
7class Course(models.Model):
8 title = models.CharField(max_length=255, db_index=True)
9 description = models.TextField(blank=True)
10 author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='courses')
11 price = models.DecimalField(max_digits=10, decimal_places=2, default=0)
12 created_at = models.DateTimeField(auto_now_add=True)
13 updated_at = models.DateTimeField(auto_now=True)
14 is_published = models.BooleanField(default=False)
15
16 class Meta:
17 ordering = ['-created_at']
18 indexes = [models.Index(fields=['author', 'is_published'])]
19
20 def __str__(self) -> str:
21 return self.title
22
23# Efficient queries — avoid N+1
24courses = (
25 Course.objects
26 .select_related('author')
27 .prefetch_related('modules')
28 .filter(is_published=True)
29 .only('id', 'title', 'author__name', 'price')
30)Views & URLs
Python
1# courses/views.py
2from django.views.generic import ListView, DetailView
3from .models import Course
4
5class PublishedCourseListView(ListView):
6 model = Course
7 template_name = 'courses/list.html'
8 context_object_name = 'courses'
9 paginate_by = 20
10
11 def get_queryset(self):
12 return Course.objects.filter(is_published=True).select_related('author')
13
14# courses/urls.py
15from django.urls import path
16from . import views
17
18urlpatterns = [
19 path('', views.PublishedCourseListView.as_view(), name='course-list'),
20 path('<int:pk>/', views.CourseDetailView.as_view(), name='course-detail'),
21]Django REST Framework
Python
1# courses/serializers.py
2from rest_framework import serializers
3from .models import Course
4
5class CourseSerializer(serializers.ModelSerializer):
6 author_name = serializers.CharField(source='author.get_full_name', read_only=True)
7
8 class Meta:
9 model = Course
10 fields = ['id', 'title', 'description', 'author_name', 'price', 'created_at']
11 read_only_fields = ['id', 'author_name', 'created_at']
12
13# courses/views.py (API)
14from rest_framework import viewsets, permissions, filters
15from django_filters.rest_framework import DjangoFilterBackend
16
17class CourseViewSet(viewsets.ModelViewSet):
18 queryset = Course.objects.filter(is_published=True).select_related('author')
19 serializer_class = CourseSerializer
20 permission_classes = [permissions.IsAuthenticatedOrReadOnly]
21 filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
22 filterset_fields = ['author']
23 search_fields = ['title', 'description']
24 ordering_fields = ['created_at', 'price']
25
26 def perform_create(self, serializer):
27 serializer.save(author=self.request.user)Authentication & Permissions
Python
1pip install djangorestframework-simplejwt
2
3# config/settings.py
4REST_FRAMEWORK = {
5 'DEFAULT_AUTHENTICATION_CLASSES': [
6 'rest_framework_simplejwt.authentication.JWTAuthentication',
7 ],
8}
9
10# courses/permissions.py
11from rest_framework.permissions import BasePermission
12
13class IsOwnerOrReadOnly(BasePermission):
14 def has_object_permission(self, request, view, obj):
15 if request.method in ('GET', 'HEAD', 'OPTIONS'):
16 return True
17 return obj.author == request.userTesting
Python
1pip install pytest pytest-django pytest-cov
2
3# pytest.ini
4[pytest]
5DJANGO_SETTINGS_MODULE = config.settings.test
6addopts = --cov=. --cov-report=term-missing --cov-fail-under=80
7
8# courses/tests/test_api.py
9import pytest
10from rest_framework.test import APIClient
11from courses.models import Course
12
13@pytest.fixture
14def client(): return APIClient()
15
16@pytest.fixture
17def user(db, django_user_model):
18 return django_user_model.objects.create_user(username='alice', password='pass')
19
20@pytest.mark.django_db
21def test_list_courses(client, user):
22 Course.objects.create(title='Django 101', author=user, is_published=True)
23 response = client.get('/api/v1/courses/')
24 assert response.status_code == 200
25 assert len(response.data['results']) == 1Performance & Caching
Python
1pip install django-redis
2
3# settings.py
4CACHES = {
5 'default': {
6 'BACKEND': 'django_redis.cache.RedisCache',
7 'LOCATION': 'redis://127.0.0.1:6379/1',
8 'OPTIONS': { 'CLIENT_CLASS': 'django_redis.client.DefaultClient' },
9 'TIMEOUT': 300,
10 }
11}
12
13# Cache a view for 5 minutes
14from django.views.decorators.cache import cache_page
15
16@cache_page(60 * 5)
17def course_list(request):
18 ...Production Deployment
Bash
1pip install gunicorn whitenoise
2
3# gunicorn.conf.py
4workers = 4
5bind = '0.0.0.0:8000'
6accesslog = '-'
7errorlog = '-'
8
9# Collect static files
10python manage.py collectstatic --noinput
11
12# Nginx upstream
13upstream django {
14 server 127.0.0.1:8000;
15}
16
17server {
18 location / { proxy_pass http://django; }
19 location /static/ { alias /app/staticfiles/; expires 1y; }
20}