Complete Django Course: Build Production Web Apps
Course Overview
This course takes you from beginner to advanced Django developer through 14 focused modules. Each module contains theory, production-grade code examples, and hands-on assignments.
Module 1: Django Setup & Project Architecture
What You Learn
- Virtual environments and Django installation
- Project vs. App structure
- MTV (Model-Template-View) architecture
Project Structure
myproject/
├── manage.py
├── myproject/
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ ├── asgi.py
│ └── wsgi.py
├── users/ # App: Authentication
├── blog/ # App: Content
├── api/ # App: REST Endpoints
└── requirements.txt
Commands
1[object Object], 2python -m venv venv 3,[object Object], venv/bin/activate ,[object Object], 4venv\Scripts\activate ,[object Object], 5 6,[object Object], 7pip install django djangorestframework 8 9,[object Object], 10django-admin startproject myproject . 11python manage.py startapp ,[object Object], 12python manage.py startapp blog 13python manage.py startapp api
Practice Task
Create a project with three apps and register them in settings.py.
Module 2: Settings.py - The Configuration Engine
Key Configurations Explained
1[object Object], 2 3,[object Object], pathlib ,[object Object], Path 4,[object Object], os 5 6BASE_DIR = Path(__file__).resolve().parent.parent 7 8,[object Object], 9SECRET_KEY = os.environ.get(,[object Object],, ,[object Object],) 10 11,[object Object], 12DEBUG = os.environ.get(,[object Object],, ,[object Object],) == ,[object Object], 13 14ALLOWED_HOSTS = [,[object Object],, ,[object Object],, ,[object Object],] 15 16,[object Object], 17INSTALLED_APPS = [ 18 ,[object Object],, 19 ,[object Object],, 20 ,[object Object],, 21 ,[object Object],, 22 ,[object Object],, 23 ,[object Object],, 24 25 ,[object Object], 26 ,[object Object],, 27 ,[object Object],, 28 ,[object Object],, 29 30 ,[object Object], 31 ,[object Object],, 32 ,[object Object],, 33 ,[object Object],, 34] 35 36MIDDLEWARE = [ 37 ,[object Object],, ,[object Object], 38 ,[object Object],, 39 ,[object Object],, 40 ,[object Object],, 41 ,[object Object],, 42 ,[object Object],, 43 ,[object Object],, 44 ,[object Object],, 45] 46 47,[object Object], 48DATABASES = { 49 ,[object Object],: { 50 ,[object Object],: ,[object Object],, 51 ,[object Object],: os.environ.get(,[object Object],, ,[object Object],), 52 ,[object Object],: os.environ.get(,[object Object],, ,[object Object],), 53 ,[object Object],: os.environ.get(,[object Object],, ,[object Object],), 54 ,[object Object],: os.environ.get(,[object Object],, ,[object Object],), 55 ,[object Object],: ,[object Object],, 56 } 57} 58 59,[object Object], 60,[object Object], 61,[object Object], 62,[object Object], 63,[object Object], 64,[object Object], 65,[object Object], 66 67,[object Object], 68AUTH_PASSWORD_VALIDATORS = [ 69 {,[object Object],: ,[object Object],}, 70 {,[object Object],: ,[object Object],, ,[object Object],: {,[object Object],: ,[object Object],}}, 71 {,[object Object],: ,[object Object],}, 72 {,[object Object],: ,[object Object],}, 73] 74 75,[object Object], 76LANGUAGE_CODE = ,[object Object], 77TIME_ZONE = ,[object Object], 78USE_I18N = ,[object Object], 79USE_TZ = ,[object Object], 80 81,[object Object], 82STATIC_URL = ,[object Object], 83STATIC_ROOT = BASE_DIR / ,[object Object], 84STATICFILES_DIRS = [BASE_DIR / ,[object Object],] 85 86MEDIA_URL = ,[object Object], 87MEDIA_ROOT = BASE_DIR / ,[object Object], 88 89,[object Object], 90DEFAULT_AUTO_FIELD = ,[object Object], 91 92,[object Object], 93REST_FRAMEWORK = { 94 ,[object Object],: [ 95 ,[object Object],, 96 ,[object Object],, 97 ], 98 ,[object Object],: [ 99 ,[object Object],, 100 ], 101 ,[object Object],: ,[object Object],, 102 ,[object Object],: ,[object Object],, 103 ,[object Object],: [ 104 ,[object Object],, 105 ,[object Object], 106 ], 107 ,[object Object],: { 108 ,[object Object],: ,[object Object],, 109 ,[object Object],: ,[object Object], 110 } 111} 112 113,[object Object], 114CORS_ALLOWED_ORIGINS = [ 115 ,[object Object],, 116 ,[object Object],, 117] 118 119,[object Object], 120AUTH_USER_MODEL = ,[object Object],
Practice Task
Move your SECRET_KEY to environment variables and configure PostgreSQL.
Module 3: Models.py - Database Design & ORM
Core Concepts
Models define your database schema. Django ORM translates Python code to SQL.
Basic Field Types
1[object Object], 2 3,[object Object], django.db ,[object Object], models 4,[object Object], django.contrib.auth ,[object Object], get_user_model 5 6User = get_user_model() 7 8,[object Object], ,[object Object],(models.Model): 9 ,[object Object], 10 created_at = models.DateTimeField(auto_now_add=,[object Object],) 11 updated_at = models.DateTimeField(auto_now=,[object Object],) 12 13 ,[object Object], ,[object Object],: 14 abstract = ,[object Object], 15 16,[object Object], ,[object Object],(,[object Object],): 17 name = models.CharField(max_length=,[object Object],, unique=,[object Object],) 18 slug = models.SlugField(max_length=,[object Object],, unique=,[object Object],) 19 description = models.TextField(blank=,[object Object],) 20 is_active = models.BooleanField(default=,[object Object],) 21 22 ,[object Object], ,[object Object],: 23 verbose_name_plural = ,[object Object], 24 ordering = [,[object Object],] 25 26 ,[object Object], ,[object Object],(,[object Object],): 27 ,[object Object], ,[object Object],.name 28 29,[object Object], ,[object Object],(,[object Object],): 30 name = models.CharField(max_length=,[object Object],, unique=,[object Object],) 31 slug = models.SlugField(max_length=,[object Object],, unique=,[object Object],) 32 33 ,[object Object], ,[object Object],(,[object Object],): 34 ,[object Object], ,[object Object],.name 35 36,[object Object], ,[object Object],(,[object Object],): 37 STATUS_CHOICES = [ 38 (,[object Object],, ,[object Object],), 39 (,[object Object],, ,[object Object],), 40 (,[object Object],, ,[object Object],), 41 ] 42 43 title = models.CharField(max_length=,[object Object],) 44 slug = models.SlugField(max_length=,[object Object],, unique=,[object Object],) 45 author = models.ForeignKey( 46 User, 47 on_delete=models.CASCADE, 48 related_name=,[object Object], 49 ) 50 category = models.ForeignKey( 51 Category, 52 on_delete=models.SET_NULL, 53 null=,[object Object],, 54 related_name=,[object Object], 55 ) 56 tags = models.ManyToManyField(Tag, related_name=,[object Object],, blank=,[object Object],) 57 content = models.TextField() 58 excerpt = models.TextField(max_length=,[object Object],, blank=,[object Object],) 59 featured_image = models.ImageField( 60 upload_to=,[object Object],, 61 blank=,[object Object],, 62 null=,[object Object], 63 ) 64 status = models.CharField( 65 max_length=,[object Object],, 66 choices=STATUS_CHOICES, 67 default=,[object Object], 68 ) 69 published_at = models.DateTimeField(null=,[object Object],, blank=,[object Object],) 70 view_count = models.PositiveIntegerField(default=,[object Object],) 71 is_featured = models.BooleanField(default=,[object Object],) 72 73 ,[object Object], ,[object Object],: 74 ordering = [,[object Object],] 75 indexes = [ 76 models.Index(fields=[,[object Object],]), 77 models.Index(fields=[,[object Object],, ,[object Object],]), 78 ] 79 80 ,[object Object], ,[object Object],(,[object Object],): 81 ,[object Object], ,[object Object],.title 82 83,[object Object], 84 ,[object Object], ,[object Object],(,[object Object],): 85 ,[object Object], 86 words = ,[object Object],(,[object Object],.content.split()) 87 ,[object Object], ,[object Object],(,[object Object],, ,[object Object],(words / ,[object Object],)) ,[object Object],
Field Types Reference
| Field | Use Case | Key Arguments |
|---|---|---|
CharField | Short strings | max_length (required) |
TextField | Long content | blank=True |
IntegerField | Whole numbers | default=0 |
PositiveIntegerField | Counts, quantities | validators |
BooleanField | True/False flags | default=False |
DateTimeField | Timestamps | auto_now_add, auto_now |
EmailField | Email addresses | unique=True |
URLField | Web links | verify_exists |
FileField | File uploads | upload_to |
ImageField | Image uploads | upload_to, requires Pillow |
JSONField | JSON data | default=dict |
UUIDField | Unique identifiers | primary_key=True, default=uuid.uuid4 |
Practice Task
Create a Product model with price (DecimalField), stock quantity, and category.
Module 4: Database Relationships Deep Dive
One-to-Many (ForeignKey)
1[object Object], ,[object Object],(,[object Object],): 2 post = models.ForeignKey( 3 Post, 4 on_delete=models.CASCADE, ,[object Object], 5 related_name=,[object Object], ,[object Object], 6 ) 7 author = models.ForeignKey(User, on_delete=models.CASCADE) 8 parent = models.ForeignKey( 9 ,[object Object],, 10 on_delete=models.CASCADE, 11 null=,[object Object],, 12 blank=,[object Object],, 13 related_name=,[object Object], 14 ) 15 content = models.TextField() 16 is_approved = models.BooleanField(default=,[object Object],) 17 18 ,[object Object], ,[object Object],: 19 ordering = [,[object Object],]
Many-to-Many
1[object Object], ,[object Object],(,[object Object],): 2 title = models.CharField(max_length=,[object Object],) 3 students = models.ManyToManyField( 4 User, 5 through=,[object Object],, ,[object Object], 6 through_fields=(,[object Object],, ,[object Object],), 7 related_name=,[object Object], 8 ) 9 instructors = models.ManyToManyField( 10 User, 11 related_name=,[object Object],, 12 limit_choices_to={,[object Object],: ,[object Object],} 13 ) 14 15,[object Object], ,[object Object],(models.Model): 16 ,[object Object], 17 student = models.ForeignKey(User, on_delete=models.CASCADE) 18 course = models.ForeignKey(Course, on_delete=models.CASCADE) 19 enrolled_at = models.DateTimeField(auto_now_add=,[object Object],) 20 completed = models.BooleanField(default=,[object Object],) 21 progress = models.PositiveSmallIntegerField(default=,[object Object],) ,[object Object], 22 23 ,[object Object], ,[object Object],: 24 unique_together = [,[object Object],, ,[object Object],] ,[object Object],
One-to-One
1[object Object], ,[object Object],(,[object Object],): 2 user = models.OneToOneField( 3 User, 4 on_delete=models.CASCADE, 5 related_name=,[object Object], 6 ) 7 bio = models.TextField(max_length=,[object Object],, blank=,[object Object],) 8 birth_date = models.DateField(null=,[object Object],, blank=,[object Object],) 9 phone = models.CharField(max_length=,[object Object],, blank=,[object Object],) 10 avatar = models.ImageField(upload_to=,[object Object],, blank=,[object Object],) 11 website = models.URLField(blank=,[object Object],) 12 13 ,[object Object], ,[object Object],(,[object Object],): 14 ,[object Object], ,[object Object],
on_delete Behaviors
| Behavior | Effect |
|---|---|
CASCADE | Delete related objects |
PROTECT | Prevent deletion if related objects exist |
SET_NULL | Set FK to NULL (requires null=True) |
SET_DEFAULT | Set FK to default value |
DO_NOTHING | Take no action (risky, manual cleanup) |
RESTRICT | Similar to PROTECT but allows if referenced elsewhere |
Migrations Commands
1python manage.py makemigrations 2python manage.py migrate 3python manage.py sqlmigrate app_name 0001 ,[object Object], 4python manage.py showmigrations
Practice Task
Build a Library system with Books, Authors, Members, and BorrowRecords.
Module 5: Custom User Model & Authentication Setup
Why Custom User Model?
Always start projects with a custom user model. Changing later is painful.
1[object Object], 2 3,[object Object], django.contrib.auth.models ,[object Object], AbstractUser 4,[object Object], django.db ,[object Object], models 5 6,[object Object], ,[object Object],(,[object Object],): 7 email = models.EmailField(unique=,[object Object],) 8 is_verified = models.BooleanField(default=,[object Object],) 9 role = models.CharField( 10 max_length=,[object Object],, 11 choices=[ 12 (,[object Object],, ,[object Object],), 13 (,[object Object],, ,[object Object],), 14 (,[object Object],, ,[object Object],), 15 (,[object Object],, ,[object Object],), 16 ], 17 default=,[object Object], 18 ) 19 20 ,[object Object], 21 USERNAME_FIELD = ,[object Object], 22 REQUIRED_FIELDS = [,[object Object],, ,[object Object],, ,[object Object],] 23 24 ,[object Object], ,[object Object],(,[object Object],): 25 ,[object Object], ,[object Object],.email
1[object Object], 2 3,[object Object], django.contrib ,[object Object], admin 4,[object Object], django.contrib.auth.admin ,[object Object], UserAdmin 5,[object Object], .models ,[object Object], CustomUser 6 7,[object Object], 8,[object Object], ,[object Object],(,[object Object],): 9 list_display = [,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],] 10 list_filter = [,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],] 11 fieldsets = UserAdmin.fieldsets + ( 12 (,[object Object],, {,[object Object],: (,[object Object],, ,[object Object],, ,[object Object],)}), 13 ) 14 add_fieldsets = UserAdmin.add_fieldsets + ( 15 (,[object Object],, {,[object Object],: (,[object Object],, ,[object Object],)}), 16 )
Practice Task
Add phone and date_joined fields to your custom user model.
Module 6: Django Admin Mastery
1[object Object], 2 3,[object Object], django.contrib ,[object Object], admin 4,[object Object], .models ,[object Object], Post, Category, Comment 5 6,[object Object], ,[object Object],(admin.TabularInline): 7 model = Comment 8 extra = ,[object Object], 9 readonly_fields = [,[object Object],] 10 11,[object Object], 12,[object Object], ,[object Object],(admin.ModelAdmin): 13 list_display = [,[object Object],, ,[object Object],, ,[object Object],] 14 list_filter = [,[object Object],] 15 search_fields = [,[object Object],, ,[object Object],] 16 prepopulated_fields = {,[object Object],: (,[object Object],,)} 17 18 ,[object Object], ,[object Object],(,[object Object],): 19 ,[object Object], obj.posts.count() 20 21,[object Object], 22,[object Object], ,[object Object],(admin.ModelAdmin): 23 list_display = [,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],] 24 list_filter = [,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],] 25 search_fields = [,[object Object],, ,[object Object],, ,[object Object],] 26 prepopulated_fields = {,[object Object],: (,[object Object],,)} 27 date_hierarchy = ,[object Object], 28 inlines = [CommentInline] 29 actions = [,[object Object],, ,[object Object],] 30 31 fieldsets = ( 32 (,[object Object],, {,[object Object],: (,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],)}), 33 (,[object Object],, {,[object Object],: (,[object Object],, ,[object Object],)}), 34 (,[object Object],, {,[object Object],: (,[object Object],,)}), 35 (,[object Object],, {,[object Object],: (,[object Object],, ,[object Object],, ,[object Object],)}), 36 (,[object Object],, {,[object Object],: (,[object Object],,), ,[object Object],: (,[object Object],,)}), 37 ) 38 39,[object Object], 40 ,[object Object], ,[object Object],(,[object Object],): 41 queryset.update(status=,[object Object],) 42 43 ,[object Object], ,[object Object],(,[object Object],): 44 ,[object Object], 45 ,[object Object], ,[object Object],().get_queryset(request).select_related(,[object Object],, ,[object Object],)
Practice Task
Create a custom admin action to export posts as CSV.
Module 7: Views.py - Request Handling
Function-Based Views (FBV)
1[object Object], 2 3,[object Object], django.shortcuts ,[object Object], render, get_object_or_404, redirect 4,[object Object], django.core.paginator ,[object Object], Paginator 5,[object Object], django.db.models ,[object Object], Q, Count 6,[object Object], django.contrib.auth.decorators ,[object Object], login_required 7,[object Object], .models ,[object Object], Post, Category 8 9,[object Object], ,[object Object],(,[object Object],): 10 ,[object Object], 11 featured_posts = Post.objects.,[object Object],( 12 is_featured=,[object Object],, 13 status=,[object Object], 14 ).select_related(,[object Object],, ,[object Object],)[:,[object Object],] 15 16 latest_posts = Post.objects.,[object Object],( 17 status=,[object Object], 18 ).select_related(,[object Object],, ,[object Object],).prefetch_related(,[object Object],)[:,[object Object],] 19 20 categories = Category.objects.annotate( 21 post_count=Count(,[object Object],) 22 ).,[object Object],(is_active=,[object Object],) 23 24 context = { 25 ,[object Object],: featured_posts, 26 ,[object Object],: latest_posts, 27 ,[object Object],: categories, 28 } 29 ,[object Object], render(request, ,[object Object],, context) 30 31,[object Object], ,[object Object],(,[object Object],): 32 ,[object Object], 33 post = get_object_or_404( 34 Post.objects.select_related(,[object Object],, ,[object Object],) 35 .prefetch_related(,[object Object],, ,[object Object],), 36 slug=slug, 37 status=,[object Object], 38 ) 39 40 ,[object Object], 41 Post.objects.,[object Object],(pk=post.pk).update(view_count=models.F(,[object Object],) + ,[object Object],) 42 43 ,[object Object], 44 related_posts = Post.objects.,[object Object],( 45 category=post.category, 46 status=,[object Object], 47 ).exclude(pk=post.pk)[:,[object Object],] 48 49 context = { 50 ,[object Object],: post, 51 ,[object Object],: related_posts, 52 ,[object Object],: post.reading_time, 53 } 54 ,[object Object], render(request, ,[object Object],, context) 55 56,[object Object], ,[object Object],(,[object Object],): 57 ,[object Object], 58 query = request.GET.get(,[object Object],, ,[object Object],) 59 60 posts = Post.objects.,[object Object],( 61 status=,[object Object], 62 ).,[object Object],( 63 Q(title__icontains=query) | 64 Q(content__icontains=query) | 65 Q(tags__name__icontains=query) 66 ).distinct() 67 68 paginator = Paginator(posts, ,[object Object],) 69 page_number = request.GET.get(,[object Object],) 70 page_obj = paginator.get_page(page_number) 71 72 ,[object Object], render(request, ,[object Object],, { 73 ,[object Object],: page_obj, 74 ,[object Object],: query, 75 ,[object Object],: posts.count(), 76 }) 77 78,[object Object], 79,[object Object], ,[object Object],(,[object Object],): 80 ,[object Object], 81 ,[object Object], request.method == ,[object Object],: 82 ,[object Object], 83 ,[object Object], 84 ,[object Object], render(request, ,[object Object],)
Class-Based Views (CBV)
1[object Object], django.views.generic ,[object Object], ListView, DetailView, CreateView, UpdateView, DeleteView 2,[object Object], django.contrib.auth.mixins ,[object Object], LoginRequiredMixin, UserPassesTestMixin 3,[object Object], django.urls ,[object Object], reverse_lazy 4 5,[object Object], ,[object Object],(,[object Object],): 6 model = Post 7 template_name = ,[object Object], 8 context_object_name = ,[object Object], 9 paginate_by = ,[object Object], 10 11 ,[object Object], ,[object Object],(,[object Object],): 12 ,[object Object], Post.objects.,[object Object],(status=,[object Object],).select_related(,[object Object],) 13 14 ,[object Object], ,[object Object],(,[object Object],): 15 context = ,[object Object],().get_context_data(**kwargs) 16 context[,[object Object],] = Category.objects.,[object Object],() 17 ,[object Object], context 18 19,[object Object], ,[object Object],(,[object Object],): 20 model = Post 21 template_name = ,[object Object], 22 slug_url_kwarg = ,[object Object], 23 query_pk_and_slug = ,[object Object], 24 25 ,[object Object], ,[object Object],(,[object Object],): 26 ,[object Object], Post.objects.,[object Object],(status=,[object Object],) 27 28,[object Object], ,[object Object],(LoginRequiredMixin, CreateView): 29 model = Post 30 fields = [,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],] 31 template_name = ,[object Object], 32 33 ,[object Object], ,[object Object],(,[object Object],): 34 form.instance.author = ,[object Object],.request.user 35 form.instance.slug = slugify(form.instance.title) 36 ,[object Object], ,[object Object],().form_valid(form) 37 38 ,[object Object], ,[object Object],(,[object Object],): 39 ,[object Object], reverse_lazy(,[object Object],, kwargs={,[object Object],: ,[object Object],.,[object Object],.slug}) 40 41,[object Object], ,[object Object],(LoginRequiredMixin, UserPassesTestMixin, UpdateView): 42 model = Post 43 fields = [,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],] 44 template_name = ,[object Object], 45 46 ,[object Object], ,[object Object],(,[object Object],): 47 post = ,[object Object],.get_object() 48 ,[object Object], ,[object Object],.request.user == post.author ,[object Object], ,[object Object],.request.user.is_staff 49 50,[object Object], ,[object Object],(LoginRequiredMixin, UserPassesTestMixin, DeleteView): 51 model = Post 52 success_url = reverse_lazy(,[object Object],) 53 54 ,[object Object], ,[object Object],(,[object Object],): 55 ,[object Object], ,[object Object],.request.user == ,[object Object],.get_object().author
URL Configuration
1[object Object], 2 3,[object Object], django.urls ,[object Object], path 4,[object Object], . ,[object Object], views 5 6app_name = ,[object Object], 7 8urlpatterns = [ 9 ,[object Object], 10 path(,[object Object],, views.home, name=,[object Object],), 11 path(,[object Object],, views.search_posts, name=,[object Object],), 12 13 ,[object Object], 14 path(,[object Object],, views.PostListView.as_view(), name=,[object Object],), 15 path(,[object Object],, views.PostDetailView.as_view(), name=,[object Object],), 16 path(,[object Object],, views.PostCreateView.as_view(), name=,[object Object],), 17 path(,[object Object],, views.PostUpdateView.as_view(), name=,[object Object],), 18 path(,[object Object],, views.PostDeleteView.as_view(), name=,[object Object],), 19]
Practice Task
Convert all FBVs in your project to CBVs.
Module 8: Forms & Validation
1[object Object], 2 3,[object Object], django ,[object Object], forms 4,[object Object], django.core.exceptions ,[object Object], ValidationError 5,[object Object], .models ,[object Object], Post, Comment 6 7,[object Object], ,[object Object],(forms.ModelForm): 8 ,[object Object], ,[object Object],: 9 model = Post 10 fields = [,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],] 11 widgets = { 12 ,[object Object],: forms.TextInput(attrs={,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],}), 13 ,[object Object],: forms.Textarea(attrs={,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],}), 14 ,[object Object],: forms.CheckboxSelectMultiple(), 15 } 16 17 ,[object Object], ,[object Object],(,[object Object],): 18 title = ,[object Object],.cleaned_data[,[object Object],] 19 ,[object Object], ,[object Object],(title) < ,[object Object],: 20 ,[object Object], ValidationError(,[object Object],) 21 ,[object Object], title 22 23 ,[object Object], ,[object Object],(,[object Object],): 24 cleaned_data = ,[object Object],().clean() 25 status = cleaned_data.get(,[object Object],) 26 content = cleaned_data.get(,[object Object],) 27 28 ,[object Object], status == ,[object Object], ,[object Object], ,[object Object],(content) < ,[object Object],: 29 ,[object Object], ValidationError({ 30 ,[object Object],: ,[object Object], 31 }) 32 ,[object Object], cleaned_data 33 34,[object Object], ,[object Object],(forms.ModelForm): 35 ,[object Object], ,[object Object],: 36 model = Comment 37 fields = [,[object Object],] 38 widgets = { 39 ,[object Object],: forms.Textarea(attrs={,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],}), 40 }
Practice Task
Add a ContactForm with email validation and honeypot spam protection.
Module 9: Django REST Framework - Serializers
Understanding Serializers
Serializers convert complex data (model instances) to native Python datatypes (JSON) and validate incoming data.
1[object Object], 2 3,[object Object], rest_framework ,[object Object], serializers 4,[object Object], django.contrib.auth ,[object Object], get_user_model 5,[object Object], blog.models ,[object Object], Post, Category, Comment, Tag 6 7User = get_user_model() 8 9,[object Object], 10 11,[object Object], ,[object Object],(serializers.ModelSerializer): 12 full_name = serializers.CharField(source=,[object Object],, read_only=,[object Object],) 13 post_count = serializers.IntegerField(source=,[object Object],, read_only=,[object Object],) 14 15 ,[object Object], ,[object Object],: 16 model = User 17 fields = [,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, 18 ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],] 19 read_only_fields = [,[object Object],, ,[object Object],, ,[object Object],] 20 21,[object Object], ,[object Object],(serializers.ModelSerializer): 22 password = serializers.CharField(write_only=,[object Object],, min_length=,[object Object],, style={,[object Object],: ,[object Object],}) 23 password_confirm = serializers.CharField(write_only=,[object Object],, style={,[object Object],: ,[object Object],}) 24 25 ,[object Object], ,[object Object],: 26 model = User 27 fields = [,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],] 28 29 ,[object Object], ,[object Object],(,[object Object],): 30 ,[object Object], data[,[object Object],] != data[,[object Object],]: 31 ,[object Object], serializers.ValidationError({,[object Object],: ,[object Object],}) 32 ,[object Object], data 33 34 ,[object Object], ,[object Object],(,[object Object],): 35 validated_data.pop(,[object Object],) 36 user = User.objects.create_user(**validated_data) 37 ,[object Object], user 38 39,[object Object], 40 41,[object Object], ,[object Object],(serializers.ModelSerializer): 42 post_count = serializers.IntegerField(source=,[object Object],, read_only=,[object Object],) 43 44 ,[object Object], ,[object Object],: 45 model = Category 46 fields = [,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],] 47 48,[object Object], 49 50,[object Object], ,[object Object],(serializers.ModelSerializer): 51 ,[object Object], ,[object Object],: 52 model = Tag 53 fields = ,[object Object], 54 55,[object Object], 56 57,[object Object], ,[object Object],(serializers.ModelSerializer): 58 author = UserSerializer(read_only=,[object Object],) 59 replies_count = serializers.IntegerField(source=,[object Object],, read_only=,[object Object],) 60 61 ,[object Object], ,[object Object],: 62 model = Comment 63 fields = [,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, 64 ,[object Object],, ,[object Object],, ,[object Object],] 65 read_only_fields = [,[object Object],, ,[object Object],] 66 67 ,[object Object], ,[object Object],(,[object Object],): 68 ,[object Object], 69 ,[object Object], value ,[object Object], value.parent: 70 ,[object Object], serializers.ValidationError(,[object Object],) 71 ,[object Object], value 72 73,[object Object], 74 75,[object Object], ,[object Object],(serializers.ModelSerializer): 76 ,[object Object], 77 author = UserSerializer(read_only=,[object Object],) 78 category = CategorySerializer(read_only=,[object Object],) 79 tag_list = TagSerializer(source=,[object Object],, many=,[object Object],, read_only=,[object Object],) 80 comment_count = serializers.IntegerField(source=,[object Object],, read_only=,[object Object],) 81 82 ,[object Object], ,[object Object],: 83 model = Post 84 fields = [ 85 ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, 86 ,[object Object],, ,[object Object],, ,[object Object],, 87 ,[object Object],, ,[object Object],, ,[object Object],, 88 ,[object Object],, ,[object Object], 89 ] 90 91,[object Object], ,[object Object],(serializers.ModelSerializer): 92 ,[object Object], 93 author = UserSerializer(read_only=,[object Object],) 94 category = CategorySerializer(read_only=,[object Object],) 95 tags = TagSerializer(many=,[object Object],, read_only=,[object Object],) 96 comments = CommentSerializer(many=,[object Object],, read_only=,[object Object],) 97 is_author = serializers.SerializerMethodField() 98 99 ,[object Object], ,[object Object],: 100 model = Post 101 fields = ,[object Object], 102 read_only_fields = [,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],] 103 104 ,[object Object], ,[object Object],(,[object Object],): 105 request = ,[object Object],.context.get(,[object Object],) 106 ,[object Object], request ,[object Object], request.user.is_authenticated: 107 ,[object Object], obj.author == request.user 108 ,[object Object], ,[object Object], 109 110 ,[object Object], ,[object Object],(,[object Object],): 111 ,[object Object], Post.objects.exclude(pk=,[object Object],.instance.pk ,[object Object], ,[object Object],.instance ,[object Object], ,[object Object],).,[object Object],(title=value).exists(): 112 ,[object Object], serializers.ValidationError(,[object Object],) 113 ,[object Object], value 114 115,[object Object], ,[object Object],(serializers.ModelSerializer): 116 ,[object Object], 117 tags = serializers.ListField( 118 child=serializers.CharField(max_length=,[object Object],), 119 write_only=,[object Object],, 120 required=,[object Object], 121 ) 122 123 ,[object Object], ,[object Object],: 124 model = Post 125 fields = [,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],, 126 ,[object Object],, ,[object Object],, ,[object Object],] 127 128 ,[object Object], ,[object Object],(,[object Object],): 129 tags_data = validated_data.pop(,[object Object],, []) 130 post = Post.objects.create(**validated_data) 131 132 ,[object Object], 133 ,[object Object], tag_name ,[object Object], tags_data: 134 tag, _ = Tag.objects.get_or_create(name=tag_name.lower().strip()) 135 post.tags.add(tag) 136 ,[object Object], post 137 138 ,[object Object], ,[object Object],(,[object Object],): 139 tags_data = validated_data.pop(,[object Object],, ,[object Object],) 140 141 ,[object Object], attr, value ,[object Object], validated_data.items(): 142 ,[object Object],(instance, attr, value) 143 instance.save() 144 145 ,[object Object], tags_data ,[object Object], ,[object Object], ,[object Object],: 146 instance.tags.clear() 147 ,[object Object], tag_name ,[object Object], tags_data: 148 tag, _ = Tag.objects.get_or_create(name=tag_name.lower().strip()) 149 instance.tags.add(tag) 150 ,[object Object], instance
Serializer Field Types
| Field | Use | Example |
|---|---|---|
CharField | Strings | max_length=100 |
IntegerField | Numbers | min_value=0 |
BooleanField | True/False | default=True |
DateTimeField | Timestamps | format='%Y-%m-%d' |
EmailField | Emails | required=True |
URLField | URLs | verify_exists=True |
SlugField | Slugs | allow_unicode=True |
FileField | Files | use_url=True |
ImageField | Images | max_length=None |
JSONField | JSON | binary=True |
SerializerMethodField | Custom logic | get_field_name() |
Practice Task
Create a serializer for the Enrollment model with validation for course capacity.
Module 10: Django REST Framework - Views & ViewSets
1[object Object], 2 3,[object Object], rest_framework ,[object Object], generics, viewsets, status, filters 4,[object Object], rest_framework.decorators ,[object Object], action 5,[object Object], rest_framework.response ,[object Object], Response 6,[object Object], rest_framework.permissions ,[object Object], IsAuthenticated, IsAuthenticatedOrReadOnly, AllowAny 7,[object Object], rest_framework.throttling ,[object Object], AnonRateThrottle, UserRateThrottle 8,[object Object], django_filters.rest_framework ,[object Object], DjangoFilterBackend 9,[object Object], django.shortcuts ,[object Object], get_object_or_404 10,[object Object], django.db.models ,[object Object], Q 11 12,[object Object], blog.models ,[object Object], Post, Category, Comment 13,[object Object], .serializers ,[object Object], ( 14 PostListSerializer, PostDetailSerializer, PostCreateUpdateSerializer, 15 CategorySerializer, CommentSerializer, UserRegistrationSerializer 16) 17,[object Object], .permissions ,[object Object], IsAuthorOrReadOnly, IsAdminOrReadOnly 18,[object Object], .pagination ,[object Object], StandardResultsSetPagination 19 20,[object Object], 21 22,[object Object], rest_framework.decorators ,[object Object], api_view, permission_classes 23 24,[object Object], 25,[object Object], 26,[object Object], ,[object Object],(,[object Object],): 27 ,[object Object], request.method == ,[object Object],: 28 categories = Category.objects.annotate(post_count=Count(,[object Object],)) 29 serializer = CategorySerializer(categories, many=,[object Object],) 30 ,[object Object], Response(serializer.data) 31 32 ,[object Object], request.method == ,[object Object],: 33 ,[object Object], ,[object Object], request.user.is_staff: 34 ,[object Object], Response({,[object Object],: ,[object Object],}, status=,[object Object],) 35 serializer = CategorySerializer(data=request.data) 36 ,[object Object], serializer.is_valid(): 37 serializer.save() 38 ,[object Object], Response(serializer.data, status=,[object Object],) 39 ,[object Object], Response(serializer.errors, status=,[object Object],) 40 41,[object Object], 42 43,[object Object], ,[object Object],(generics.ListCreateAPIView): 44 ,[object Object], 45 queryset = Post.objects.,[object Object],(status=,[object Object],) 46 pagination_class = StandardResultsSetPagination 47 filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter] 48 filterset_fields = [,[object Object],, ,[object Object],, ,[object Object],, ,[object Object],] 49 search_fields = [,[object Object],, ,[object Object],, ,[object Object],] 50 ordering_fields = [,[object Object],, ,[object Object],, ,[object Object],] 51 ordering = [,[object Object],] 52 53 ,[object Object], ,[object Object],(,[object Object],): 54 ,[object Object], ,[object Object],.request.method == ,[object Object],: 55 ,[object Object], PostCreateUpdateSerializer 56 ,[object Object], PostListSerializer 57 58 ,[object Object], ,[object Object],(,[object Object],): 59 ,[object Object], ,[object Object],.request.method == ,[object Object],: 60 ,[object Object], [IsAuthenticated()] 61 ,[object Object], [IsAuthenticatedOrReadOnly()] 62 63 ,[object Object], ,[object Object],(,[object Object],): 64 serializer.save(author=,[object Object],.request.user) 65 66,[object Object], ,[object Object],(generics.RetrieveUpdateDestroyAPIView): 67 queryset = Post.objects.,[object Object],() 68 lookup_field = ,[object Object], 69 permission_classes = [IsAuthorOrReadOnly] 70 71 ,[object Object], ,[object Object],(,[object Object],): 72 ,[object Object], ,[object Object],.request.method ,[object Object], [,[object Object],, ,[object Object],]: 73 ,[object Object], PostCreateUpdateSerializer 74 ,[object Object], PostDetailSerializer 75 76 ,[object Object], ,[object Object],(,[object Object],): 77 instance = ,[object Object],.get_object() 78 ,[object Object], 79 Post.objects.,[object Object],(pk=instance.pk).update(view_count=F(,[object Object],) + ,[object Object],) 80 serializer = ,[object Object],.get_serializer(instance) 81 ,[object Object], Response(serializer.data) 82 83,[object Object], 84 85,[object Object], ,[object Object],(viewsets.ModelViewSet): 86 serializer_class = CommentSerializer 87 permission_classes = [IsAuthenticatedOrReadOnly, IsAuthorOrReadOnly] 88 89 ,[object Object], ,[object Object],(,[object Object],): 90 post_slug = ,[object Object],.kwargs.get(,[object Object],) 91 ,[object Object], post_slug: 92 ,[object Object], Comment.objects.,[object Object],(post__slug=post_slug, is_approved=,[object Object],) 93 ,[object Object], Comment.objects.,[object Object],(author=,[object Object],.request.user) 94 95 ,[object Object], ,[object Object],(,[object Object],): 96 post = get_object_or_404(Post, slug=,[object Object],.kwargs.get(,[object Object],)) 97 serializer.save(author=,[object Object],.request.user, post=post) 98 99,[object Object], 100 ,[object Object], ,[object Object],(,[object Object],): 101 ,[object Object], 102 comment = ,[object Object],.get_object() 103 ,[object Object], ,[object Object], request.user.is_staff: 104 ,[object Object], Response({,[object Object],: ,[object Object],}, status=,[object Object],) 105 comment.is_approved = ,[object Object], 106 comment.save() 107 ,[object Object], Response({,[object Object],: ,[object Object],}) 108 109,[object Object], 110 111,[object Object], ,[object Object],(generics.CreateAPIView): 112 serializer_class = UserRegistrationSerializer 113 permission_classes = [AllowAny] 114 throttle_classes = [AnonRateThrottle] 115 116 ,[object Object], ,[object Object],(,[object Object],): 117 serializer = ,[object Object],.get_serializer(data=request.data) 118 serializer.is_valid(raise_exception=,[object Object],) 119 user = serializer.save() 120 ,[object Object], Response({ 121 ,[object Object],: UserSerializer(user, context=,[object Object],.get_serializer_context()).data, 122 ,[object Object],: ,[object Object], 123 }, status=status.HTTP_201_CREATED)
Custom Permissions
1[object Object], 2 3,[object Object], rest_framework ,[object Object], permissions 4 5,[object Object], ,[object Object],(permissions.BasePermission): 6 ,[object Object], ,[object Object],(,[object Object],): 7 ,[object Object], request.method ,[object Object], permissions.SAFE_METHODS: 8 ,[object Object], ,[object Object], 9 ,[object Object], obj.author == request.user ,[object Object], request.user.is_staff 10 11,[object Object], ,[object Object],(permissions.BasePermission): 12 ,[object Object], ,[object Object],(,[object Object],): 13 ,[object Object], request.method ,[object Object], permissions.SAFE_METHODS: 14 ,[object Object], ,[object Object], 15 ,[object Object], request.user ,[object Object], request.user.is_staff 16 17,[object Object], ,[object Object],(permissions.BasePermission): 18 ,[object Object], ,[object Object],(,[object Object],): 19 ,[object Object], request.user ,[object Object], request.user.is_authenticated ,[object Object], request.user.is_verified
URL Router for ViewSets
1[object Object], 2 3,[object Object], django.urls ,[object Object], path, include 4,[object Object], rest_framework.routers ,[object Object], DefaultRouter 5,[object Object], . ,[object Object], views 6 7router = DefaultRouter() 8router.register(,[object Object],, views.CommentViewSet, basename=,[object Object],) 9 10urlpatterns = [ 11 path(,[object Object],, include(router.urls)), 12 path(,[object Object],, views.PostListCreateView.as_view(), name=,[object Object],), 13 path(,[object Object],, views.PostRetrieveUpdateDestroyView.as_view(), name=,[object Object],), 14 path(,[object Object],, views.CommentViewSet.as_view({,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],})), 15 path(,[object Object],, views.category_list, name=,[object Object],), 16 path(,[object Object],, views.RegisterView.as_view(), name=,[object Object],), 17]
Practice Task
Build a Like/Unlike API endpoint using @action decorator.
Module 11: Authentication & Authorization System
Token Authentication Setup
1[object Object], 2 3,[object Object], rest_framework.authentication ,[object Object], TokenAuthentication 4,[object Object], rest_framework.exceptions ,[object Object], AuthenticationFailed 5,[object Object], django.contrib.auth ,[object Object], get_user_model 6 7User = get_user_model() 8 9,[object Object], ,[object Object],(,[object Object],): 10 keyword = ,[object Object], 11 12,[object Object], 13,[object Object], 14,[object Object], 15,[object Object],
JWT Authentication (Recommended)
1pip install djangorestframework-simplejwt
1[object Object], 2 3REST_FRAMEWORK = { 4 ,[object Object],: [ 5 ,[object Object],, 6 ], 7} 8 9,[object Object], 10,[object Object], rest_framework_simplejwt.views ,[object Object], ( 11 TokenObtainPairView, 12 TokenRefreshView, 13 TokenVerifyView, 14) 15 16urlpatterns = [ 17 path(,[object Object],, TokenObtainPairView.as_view(), name=,[object Object],), 18 path(,[object Object],, TokenRefreshView.as_view(), name=,[object Object],), 19 path(,[object Object],, TokenVerifyView.as_view(), name=,[object Object],), 20]
Custom JWT Payload
1[object Object], 2 3,[object Object], rest_framework_simplejwt.serializers ,[object Object], TokenObtainPairSerializer 4 5,[object Object], ,[object Object],(,[object Object],): 6,[object Object], 7 ,[object Object], ,[object Object],(,[object Object],): 8 token = ,[object Object],().get_token(user) 9 ,[object Object], 10 token[,[object Object],] = user.username 11 token[,[object Object],] = user.email 12 token[,[object Object],] = user.role 13 token[,[object Object],] = user.is_verified 14 ,[object Object], token 15 16,[object Object], 17,[object Object], rest_framework_simplejwt.views ,[object Object], TokenObtainPairView 18 19,[object Object], ,[object Object],(,[object Object],): 20 serializer_class = CustomTokenObtainPairSerializer
Login/Register API (Complete)
1[object Object], 2 3,[object Object], rest_framework.views ,[object Object], APIView 4,[object Object], rest_framework_simplejwt.tokens ,[object Object], RefreshToken 5,[object Object], django.contrib.auth ,[object Object], authenticate 6 7,[object Object], ,[object Object],(,[object Object],): 8 permission_classes = [AllowAny] 9 10 ,[object Object], ,[object Object],(,[object Object],): 11 email = request.data.get(,[object Object],) 12 password = request.data.get(,[object Object],) 13 14 user = authenticate(request, username=email, password=password) 15 ,[object Object], user: 16 refresh = RefreshToken.for_user(user) 17 ,[object Object], Response({ 18 ,[object Object],: ,[object Object],(refresh), 19 ,[object Object],: ,[object Object],(refresh.access_token), 20 ,[object Object],: UserSerializer(user).data, 21 }) 22 ,[object Object], Response({,[object Object],: ,[object Object],}, status=,[object Object],) 23 24,[object Object], ,[object Object],(,[object Object],): 25 permission_classes = [IsAuthenticated] 26 27 ,[object Object], ,[object Object],(,[object Object],): 28 ,[object Object],: 29 refresh_token = request.data.get(,[object Object],) 30 token = RefreshToken(refresh_token) 31 token.blacklist() ,[object Object], 32 ,[object Object], Response({,[object Object],: ,[object Object],}) 33 ,[object Object], Exception ,[object Object], e: 34 ,[object Object], Response({,[object Object],: ,[object Object],(e)}, status=,[object Object],) 35 36,[object Object], ,[object Object],(,[object Object],): 37 permission_classes = [IsAuthenticated] 38 39 ,[object Object], ,[object Object],(,[object Object],): 40 user = request.user 41 old_password = request.data.get(,[object Object],) 42 new_password = request.data.get(,[object Object],) 43 44 ,[object Object], ,[object Object], user.check_password(old_password): 45 ,[object Object], Response({,[object Object],: ,[object Object],}, status=,[object Object],) 46 47 user.set_password(new_password) 48 user.save() 49 ,[object Object], Response({,[object Object],: ,[object Object],})
Practice Task
Implement email verification using Django's send_mail and token generation.
Module 12: User Registration with Email Verification
1[object Object], 2 3,[object Object], django.core.mail ,[object Object], send_mail 4,[object Object], django.contrib.auth.tokens ,[object Object], default_token_generator 5,[object Object], django.utils.http ,[object Object], urlsafe_base64_encode, urlsafe_base64_decode 6,[object Object], django.utils.encoding ,[object Object], force_bytes, force_str 7,[object Object], django.urls ,[object Object], reverse 8,[object Object], django.conf ,[object Object], settings 9 10,[object Object], ,[object Object],(generics.CreateAPIView): 11 serializer_class = UserRegistrationSerializer 12 permission_classes = [AllowAny] 13 14 ,[object Object], ,[object Object],(,[object Object],): 15 serializer = ,[object Object],.get_serializer(data=request.data) 16 serializer.is_valid(raise_exception=,[object Object],) 17 user = serializer.save() 18 user.is_active = ,[object Object], ,[object Object], 19 user.save() 20 21 ,[object Object], 22 token = default_token_generator.make_token(user) 23 uid = urlsafe_base64_encode(force_bytes(user.pk)) 24 25 verification_url = request.build_absolute_uri( 26 reverse(,[object Object],, kwargs={,[object Object],: uid, ,[object Object],: token}) 27 ) 28 29 ,[object Object], 30 send_mail( 31 subject=,[object Object],, 32 message=,[object Object],, 33 from_email=settings.DEFAULT_FROM_EMAIL, 34 recipient_list=[user.email], 35 fail_silently=,[object Object],, 36 ) 37 38 ,[object Object], Response({ 39 ,[object Object],: ,[object Object], 40 }, status=,[object Object],) 41 42,[object Object], ,[object Object],(,[object Object],): 43 permission_classes = [AllowAny] 44 45 ,[object Object], ,[object Object],(,[object Object],): 46 ,[object Object],: 47 uid = force_str(urlsafe_base64_decode(uidb64)) 48 user = User.objects.get(pk=uid) 49 ,[object Object], (TypeError, ValueError, OverflowError, User.DoesNotExist): 50 user = ,[object Object], 51 52 ,[object Object], user ,[object Object], default_token_generator.check_token(user, token): 53 user.is_active = ,[object Object], 54 user.is_verified = ,[object Object], 55 user.save() 56 ,[object Object], Response({,[object Object],: ,[object Object],}) 57 ,[object Object], Response({,[object Object],: ,[object Object],}, status=,[object Object],)
Password Reset Flow
1[object Object], ,[object Object],(,[object Object],): 2 permission_classes = [AllowAny] 3 4 ,[object Object], ,[object Object],(,[object Object],): 5 email = request.data.get(,[object Object],) 6 ,[object Object],: 7 user = User.objects.get(email=email) 8 token = default_token_generator.make_token(user) 9 uid = urlsafe_base64_encode(force_bytes(user.pk)) 10 11 reset_url = request.build_absolute_uri( 12 reverse(,[object Object],, kwargs={,[object Object],: uid, ,[object Object],: token}) 13 ) 14 15 send_mail( 16 subject=,[object Object],, 17 message=,[object Object],, 18 from_email=settings.DEFAULT_FROM_EMAIL, 19 recipient_list=[email], 20 ) 21 ,[object Object], Response({,[object Object],: ,[object Object],}) 22 ,[object Object], User.DoesNotExist: 23 ,[object Object], 24 ,[object Object], Response({,[object Object],: ,[object Object],}) 25 26,[object Object], ,[object Object],(,[object Object],): 27 permission_classes = [AllowAny] 28 29 ,[object Object], ,[object Object],(,[object Object],): 30 ,[object Object],: 31 uid = force_str(urlsafe_base64_decode(uidb64)) 32 user = User.objects.get(pk=uid) 33 ,[object Object], (TypeError, ValueError, OverflowError, User.DoesNotExist): 34 user = ,[object Object], 35 36 ,[object Object], user ,[object Object], default_token_generator.check_token(user, token): 37 new_password = request.data.get(,[object Object],) 38 user.set_password(new_password) 39 user.save() 40 ,[object Object], Response({,[object Object],: ,[object Object],}) 41 ,[object Object], Response({,[object Object],: ,[object Object],}, status=,[object Object],)
Practice Task
Add rate limiting to password reset requests (max 3 per hour).
Module 13: Middleware, Signals & Performance
Custom Middleware
1[object Object], 2 3,[object Object], time 4,[object Object], logging 5,[object Object], django.http ,[object Object], JsonResponse 6 7logger = logging.getLogger(,[object Object],) 8 9,[object Object], ,[object Object],: 10 ,[object Object], ,[object Object],(,[object Object],): 11 ,[object Object],.get_response = get_response 12 13 ,[object Object], ,[object Object],(,[object Object],): 14 start_time = time.time() 15 response = ,[object Object],.get_response(request) 16 duration = time.time() - start_time 17 18 response[,[object Object],] = ,[object Object], 19 logger.info(,[object Object],) 20 21 ,[object Object], response 22 23,[object Object], ,[object Object],: 24 ,[object Object], ,[object Object],(,[object Object],): 25 ,[object Object],.get_response = get_response 26 27 ,[object Object], ,[object Object],(,[object Object],): 28 version = request.headers.get(,[object Object],, ,[object Object],) 29 request.api_version = version 30 ,[object Object], ,[object Object],.get_response(request) 31 32,[object Object], 33MIDDLEWARE = [ 34 ,[object Object],, ,[object Object], 35 ,[object Object], 36]
Django Signals
1[object Object], 2 3,[object Object], django.db.models.signals ,[object Object], post_save, pre_delete 4,[object Object], django.dispatch ,[object Object], receiver 5,[object Object], django.core.mail ,[object Object], send_mail 6,[object Object], django.conf ,[object Object], settings 7 8,[object Object], .models ,[object Object], CustomUser 9,[object Object], blog.models ,[object Object], Post 10 11,[object Object], 12,[object Object], ,[object Object],(,[object Object],): 13 ,[object Object], 14 ,[object Object], created: 15 Profile.objects.create(user=instance) 16 ,[object Object], 17 send_mail( 18 subject=,[object Object],, 19 message=,[object Object],, 20 from_email=settings.DEFAULT_FROM_EMAIL, 21 recipient_list=[instance.email], 22 ) 23 24,[object Object], 25,[object Object], ,[object Object],(,[object Object],): 26 instance.profile.save() 27 28,[object Object], 29,[object Object], ,[object Object],(,[object Object],): 30 ,[object Object], 31 ,[object Object], created ,[object Object], instance.status == ,[object Object],: 32 ,[object Object], 33 ,[object Object], 34 35,[object Object], 36,[object Object], django.apps ,[object Object], AppConfig 37 38,[object Object], ,[object Object],(,[object Object],): 39 default_auto_field = ,[object Object], 40 name = ,[object Object], 41 42 ,[object Object], ,[object Object],(,[object Object],): 43 ,[object Object], users.signals ,[object Object],
Query Optimization
1[object Object], 2posts = Post.objects.,[object Object],() 3,[object Object], post ,[object Object], posts: 4 ,[object Object],(post.author.username) ,[object Object], 5 6,[object Object], 7posts = Post.objects.select_related(,[object Object],, ,[object Object],).,[object Object],() 8 9,[object Object], 10posts = Post.objects.prefetch_related(,[object Object],, ,[object Object],).,[object Object],() 11 12,[object Object], 13posts = Post.objects.annotate(comment_count=Count(,[object Object],)) 14 15,[object Object], 16posts = Post.objects.only(,[object Object],, ,[object Object],, ,[object Object],) 17 18,[object Object], 19posts = Post.objects.defer(,[object Object],) ,[object Object], 20 21,[object Object], 22,[object Object], Post.objects.,[object Object],(status=,[object Object],).exists(): 23 ,[object Object], 24 25,[object Object], 26count = Post.objects.,[object Object],(status=,[object Object],).count() 27 28,[object Object], 29Post.objects.bulk_create([Post(title=,[object Object],) ,[object Object], i ,[object Object], ,[object Object],(,[object Object],)]) 30Post.objects.,[object Object],(status=,[object Object],).update(status=,[object Object],)
Caching
1[object Object], django.core.cache ,[object Object], cache 2,[object Object], django.views.decorators.cache ,[object Object], cache_page 3,[object Object], django.utils.decorators ,[object Object], method_decorator 4 5,[object Object], 6,[object Object],[object Object], 7,[object Object], ,[object Object],(,[object Object],): 8 posts = Post.objects.,[object Object],() 9 ,[object Object], render(request, ,[object Object],, {,[object Object],: posts}) 10 11,[object Object], 12,[object Object], ,[object Object],(): 13 cache_key = ,[object Object], 14 posts = cache.get(cache_key) 15 ,[object Object], posts ,[object Object], ,[object Object],: 16 posts = Post.objects.order_by(,[object Object],)[:,[object Object],] 17 cache.,[object Object],(cache_key, posts, ,[object Object], * ,[object Object],) ,[object Object], 18 ,[object Object], posts 19 20,[object Object], 21,[object Object], ,[object Object],(,[object Object],): 22 cache.delete(,[object Object],) 23 cache.delete(,[object Object],)
Practice Task
Implement Redis caching for your API responses.
Module 14: Testing in Django
1[object Object], 2 3,[object Object], django.test ,[object Object], TestCase, Client 4,[object Object], django.urls ,[object Object], reverse 5,[object Object], django.contrib.auth ,[object Object], get_user_model 6,[object Object], rest_framework.test ,[object Object], APITestCase, APIClient 7,[object Object], rest_framework ,[object Object], status 8 9,[object Object], .models ,[object Object], Post, Category 10 11User = get_user_model() 12 13,[object Object], ,[object Object],(,[object Object],): 14 ,[object Object], ,[object Object],(,[object Object],): 15 ,[object Object],.user = User.objects.create_user( 16 username=,[object Object],, 17 email=,[object Object],, 18 password=,[object Object], 19 ) 20 ,[object Object],.category = Category.objects.create(name=,[object Object],, slug=,[object Object],) 21 ,[object Object],.post = Post.objects.create( 22 title=,[object Object],, 23 slug=,[object Object],, 24 author=,[object Object],.user, 25 category=,[object Object],.category, 26 content=,[object Object],, 27 status=,[object Object], 28 ) 29 30 ,[object Object], ,[object Object],(,[object Object],): 31 ,[object Object],.assertEqual(,[object Object],.post.title, ,[object Object],) 32 ,[object Object],.assertEqual(,[object Object],(,[object Object],.post), ,[object Object],) 33 ,[object Object],.assertTrue(,[object Object],.post.slug) 34 35 ,[object Object], ,[object Object],(,[object Object],): 36 ,[object Object],.assertEqual(,[object Object],.post.reading_time, ,[object Object],) 37 38 ,[object Object], ,[object Object],(,[object Object],): 39 ,[object Object], 40 ,[object Object], 41 42,[object Object], ,[object Object],(,[object Object],): 43 ,[object Object], ,[object Object],(,[object Object],): 44 ,[object Object],.client = APIClient() 45 ,[object Object],.user = User.objects.create_user( 46 username=,[object Object],, 47 email=,[object Object],, 48 password=,[object Object], 49 ) 50 ,[object Object],.category = Category.objects.create(name=,[object Object],, slug=,[object Object],) 51 ,[object Object],.post = Post.objects.create( 52 title=,[object Object],, 53 slug=,[object Object],, 54 author=,[object Object],.user, 55 category=,[object Object],.category, 56 content=,[object Object],, 57 status=,[object Object], 58 ) 59 60 ,[object Object], ,[object Object],(,[object Object],): 61 url = reverse(,[object Object],) 62 response = ,[object Object],.client.get(url) 63 ,[object Object],.assertEqual(response.status_code, status.HTTP_200_OK) 64 ,[object Object],.assertEqual(,[object Object],(response.data[,[object Object],]), ,[object Object],) 65 66 ,[object Object], ,[object Object],(,[object Object],): 67 ,[object Object],.client.force_authenticate(user=,[object Object],.user) 68 url = reverse(,[object Object],) 69 data = { 70 ,[object Object],: ,[object Object],, 71 ,[object Object],: ,[object Object],, 72 ,[object Object],: ,[object Object],.category.,[object Object],, 73 ,[object Object],: ,[object Object], 74 } 75 response = ,[object Object],.client.post(url, data) 76 ,[object Object],.assertEqual(response.status_code, status.HTTP_201_CREATED) 77 78 ,[object Object], ,[object Object],(,[object Object],): 79 url = reverse(,[object Object],) 80 data = {,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],} 81 response = ,[object Object],.client.post(url, data) 82 ,[object Object],.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) 83 84 ,[object Object], ,[object Object],(,[object Object],): 85 ,[object Object],.client.force_authenticate(user=,[object Object],.user) 86 url = reverse(,[object Object],, kwargs={,[object Object],: ,[object Object],.post.slug}) 87 data = {,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],} 88 response = ,[object Object],.client.patch(url, data) 89 ,[object Object],.assertEqual(response.status_code, status.HTTP_200_OK) 90 ,[object Object],.post.refresh_from_db() 91 ,[object Object],.assertEqual(,[object Object],.post.title, ,[object Object],) 92 93,[object Object], ,[object Object],(,[object Object],): 94 ,[object Object], ,[object Object],(,[object Object],): 95 url = reverse(,[object Object],) 96 data = { 97 ,[object Object],: ,[object Object],, 98 ,[object Object],: ,[object Object],, 99 ,[object Object],: ,[object Object],, 100 ,[object Object],: ,[object Object],, 101 ,[object Object],: ,[object Object],, 102 ,[object Object],: ,[object Object], 103 } 104 response = ,[object Object],.client.post(url, data) 105 ,[object Object],.assertEqual(response.status_code, status.HTTP_201_CREATED) 106 ,[object Object],.assertEqual(User.objects.count(), ,[object Object],) 107 ,[object Object],.assertEqual(User.objects.get().email, ,[object Object],) 108 109 ,[object Object], ,[object Object],(,[object Object],): 110 User.objects.create_user(username=,[object Object],, email=,[object Object],, password=,[object Object],) 111 url = reverse(,[object Object],) 112 response = ,[object Object],.client.post(url, {,[object Object],: ,[object Object],, ,[object Object],: ,[object Object],}) 113 ,[object Object],.assertEqual(response.status_code, status.HTTP_200_OK) 114 ,[object Object],.assertIn(,[object Object],, response.data) 115 ,[object Object],.assertIn(,[object Object],, response.data)
Running Tests
1[object Object], 2python manage.py ,[object Object], 3 4,[object Object], 5python manage.py ,[object Object], blog 6 7,[object Object], 8python manage.py ,[object Object], blog.tests.PostModelTest 9 10,[object Object], 11coverage run --,[object Object],=,[object Object], manage.py ,[object Object], 12coverage report 13coverage html
Practice Task
Write tests for the Comment model and its API endpoints.
Module 15: Deployment & Production
Production Settings
1[object Object], 2 3,[object Object], .base ,[object Object], * 4 5DEBUG = ,[object Object], 6ALLOWED_HOSTS = [,[object Object],, ,[object Object],] 7 8,[object Object], 9SECURE_SSL_REDIRECT = ,[object Object], 10SESSION_COOKIE_SECURE = ,[object Object], 11CSRF_COOKIE_SECURE = ,[object Object], 12SECURE_BROWSER_XSS_FILTER = ,[object Object], 13SECURE_CONTENT_TYPE_NOSNIFF = ,[object Object], 14X_FRAME_OPTIONS = ,[object Object], 15SECURE_HSTS_SECONDS = ,[object Object], ,[object Object], 16SECURE_HSTS_INCLUDE_SUBDOMAINS = ,[object Object], 17SECURE_HSTS_PRELOAD = ,[object Object], 18 19,[object Object], 20DATABASES = { 21 ,[object Object],: { 22 ,[object Object],: ,[object Object],, 23 ,[object Object],: os.environ[,[object Object],], 24 ,[object Object],: os.environ[,[object Object],], 25 ,[object Object],: os.environ[,[object Object],], 26 ,[object Object],: os.environ[,[object Object],], 27 ,[object Object],: ,[object Object],, 28 ,[object Object],: ,[object Object],, ,[object Object], 29 } 30} 31 32,[object Object], 33MIDDLEWARE = [ 34 ,[object Object],, 35 ,[object Object],, ,[object Object], 36 ,[object Object], 37] 38 39STATICFILES_STORAGE = ,[object Object], 40 41,[object Object], 42LOGGING = { 43 ,[object Object],: ,[object Object],, 44 ,[object Object],: ,[object Object],, 45 ,[object Object],: { 46 ,[object Object],: { 47 ,[object Object],: ,[object Object],, 48 ,[object Object],: ,[object Object],, 49 ,[object Object],: ,[object Object],, 50 }, 51 }, 52 ,[object Object],: { 53 ,[object Object],: { 54 ,[object Object],: [,[object Object],], 55 ,[object Object],: ,[object Object],, 56 ,[object Object],: ,[object Object],, 57 }, 58 }, 59} 60 61,[object Object], 62EMAIL_BACKEND = ,[object Object], 63EMAIL_HOST = ,[object Object], 64EMAIL_PORT = ,[object Object], 65EMAIL_USE_TLS = ,[object Object], 66EMAIL_HOST_USER = ,[object Object], 67EMAIL_HOST_PASSWORD = os.environ[,[object Object],]
Gunicorn Configuration
1[object Object], 2 3bind = ,[object Object], 4workers = ,[object Object], ,[object Object], 5worker_class = ,[object Object], 6worker_connections = ,[object Object], 7timeout = ,[object Object], 8keepalive = ,[object Object], 9errorlog = ,[object Object], 10accesslog = ,[object Object], 11capture_output = ,[object Object], 12enable_stdio_inheritance = ,[object Object],
Dockerfile
1FROM python:3.11-slim 2 3WORKDIR /app 4 5ENV PYTHONDONTWRITEBYTECODE=1 6ENV PYTHONUNBUFFERED=1 7 8RUN apt-get update && apt-get install -y \ 9 gcc \ 10 libpq-dev \ 11 && rm -rf /var/lib/apt/lists/* 12 13COPY requirements.txt . 14RUN pip install --no-cache-dir -r requirements.txt 15 16COPY . . 17 18RUN python manage.py collectstatic --noinput 19 20EXPOSE 8000 21 22CMD ["gunicorn", "--config", "gunicorn.conf.py", "myproject.wsgi:application"]
Practice Task
Deploy your Django app to Render or Railway with PostgreSQL.
Final Project: Build a Complete Blog API
Combine all modules to build:
- Custom User model with email verification
- Post/Category/Tag/Comment models with relationships
- REST API with serializers and ViewSets
- JWT authentication
- Role-based permissions (Reader/Author/Admin)
- Search, filter, and pagination
- Email notifications
- Comprehensive tests
- Production deployment
Quick Reference Cheat Sheet
| Task | Command |
|---|---|
| Start project | django-admin startproject name . |
| Start app | python manage.py startapp name |
| Run server | python manage.py runserver |
| Make migrations | python manage.py makemigrations |
| Migrate | python manage.py migrate |
| Create superuser | python manage.py createsuperuser |
| Shell | python manage.py shell |
| Collect static | python manage.py collectstatic |
| Test | python manage.py test |
| Check deployment | python manage.py check --deploy |
Happy Coding! 🚀