🎯 Django Framework

The Web Framework for Perfectionists with Deadlines

πŸ‘‹ Welcome to Django!

Django is a high-level Python web framework that makes building web applications fast and easy. It's used by Instagram, Spotify, YouTube, and thousands of other companies to build robust web applications.

If you know Python basics, you're ready to learn Django!

🎯 Your Django Mastery Journey - Complete Learning Roadmap

Welcome to the most comprehensive Django learning experience available! This guide provides an exhaustive, hands-on journey through Django development, designed to take you from beginner to professional-level competence. Each section is crafted with meticulous detail, featuring 50+ practical exercises, real-world projects, advanced techniques, and complete working examples.

Our approach goes beyond basic tutorials. We explore theoretical foundations, architectural patterns, performance optimization, security best practices, testing strategies, deployment methodologies, and advanced Django ecosystem concepts. Whether you're building your first web app or scaling enterprise applications, this guide will equip you with the expertise to excel in Django development.

πŸ“š Comprehensive Learning Structure (15+ Major Sections)

  1. Introduction & Foundation (325+ learning concepts) - Django philosophy, ecosystem, career paths
  2. Environment Setup - Virtual environments, dependencies, development workflow
  3. Project Architecture - Apps vs Projects, Django design patterns
  4. Models & Database Layer - ORM, migrations, relationships, queries
  5. Views & URL Routing - Function-based & class-based views, URL patterns
  6. Templates & Frontend - Django template language, static files, asset management
  7. Forms & User Input - Model forms, validation, custom fields
  8. Authentication & Authorization - Users, permissions, sessions, security
  9. Admin Interface - Customization, permissions, advanced features
  10. REST APIs with Django - API design, serialization, authentication
  11. Testing & Debugging - Unit tests, integration tests, debugging techniques
  12. Deployment & Production - Server configuration, security hardening
  13. Performance Optimization - Caching, database optimization, CDN integration
  14. Advanced Features - Signals, middleware, custom management commands
  15. Real-World Projects - Complete applications with best practices

🎯 Learning Objectives

By the end of this comprehensive guide, you will be able to:

  • βœ… Design and implement complete web applications using Django
  • βœ… Work with Django's ORM for complex database operations
  • βœ… Create dynamic user interfaces with Django templates
  • βœ… Implement user authentication and authorization systems
  • βœ… Build and customize Django admin interfaces
  • βœ… Develop REST APIs for mobile and frontend integration
  • βœ… Deploy Django applications to production servers
  • βœ… Optimize Django applications for performance and scalability
  • βœ… Write comprehensive tests for Django applications
  • βœ… Follow Django best practices and security guidelines

πŸ“Š Learning Intensity Scale

Each major section contains extensive content including:

  • πŸ”Έ Deep theoretical explanations with architectural insights
  • πŸ”Έ 100+ hands-on exercises with complete solutions
  • πŸ”Έ Real-world case studies from industry applications
  • πŸ”Έ Performance optimization techniques
  • πŸ”Έ Security best practices and common vulnerabilities
  • πŸ”Έ Debugging strategies and troubleshooting guides
  • πŸ”Έ Code reviews and refactoring techniques
  • πŸ”Έ Integration with modern frontend frameworks

πŸš€ Career Advancement

Django Developer Career Path:

  1. Junior Django Developer - $45,000 - $65,000/year
  2. Django Developer - $65,000 - $95,000/year
  3. Senior Django Developer - $95,000 - $130,000/year
  4. Django Technical Lead - $120,000 - $160,000/year
  5. Full-Stack Architect - $140,000 - $200,000+/year

*Salaries based on US averages from major tech job boards

πŸ“ Pre-Course Assessment: Are You Ready for Django?

Before diving into Django, let's verify your Python foundation. Complete this assessment to ensure you're prepared for the course content.

βœ… You should know these concepts:

  • Python variables, data types (strings, lists, dictionaries)
  • Control flow (if/else, loops)
  • Function definitions and calling
  • Basic OOP concepts (classes, objects)
  • File handling (reading/writing files)
  • Working with virtual environments

Don't worry if you're not familiar with everything - we'll provide resources to catch up! If you score below 70%, consider completing our Python Basics course first.

πŸ€” What is Django?

Django is a free, open-source web framework written in Python. It follows the "batteries included" philosophy, meaning it comes with everything you need to build a complete web application right out of the box.

Why Choose Django?

  • πŸš€ Fast Development: Build applications in hours, not weeks
  • πŸ”’ Secure by Default: Protection against common security threats
  • πŸ“ˆ Scalable: From small projects to enterprise applications
  • πŸ›‘οΈ Batteries Included: Admin panel, ORM, authentication built-in
  • πŸ‘₯ Huge Community: Extensive documentation and support
  • 🐍 Python-Based: Clean, readable code

🌟 Companies Using Django

πŸ“Έ

Instagram

Photo sharing platform serving billions of users

🎡

Spotify

Music streaming service with millions of songs

πŸ“Ί

YouTube

Video sharing platform (parts of it)

πŸ“¦

Dropbox

File hosting and cloud storage

πŸ“Œ

Pinterest

Image sharing and discovery platform

πŸ’¬

Disqus

Comment system used by millions of sites

πŸ“‹ Prerequisites

Required Knowledge

  • βœ… Python Basics: Variables, functions, classes
  • βœ… HTML/CSS: Basic web markup
  • βœ… Command Line: Basic terminal commands

Required Software

  • βœ… Python 3.8+: Latest version recommended
  • βœ… Text Editor: VS Code, PyCharm, or similar
  • βœ… Web Browser: Chrome, Firefox, Edge

πŸš€ Installation & Setup

Step 1: Verify Python Installation

# Check Python version (must be 3.8 or higher) python --version # Output: Python 3.11.5 # Check pip (Python package manager) pip --version # Output: pip 23.x.x

Step 2: Create Virtual Environment

# Create virtual environment python -m venv myenv # Activate virtual environment # On Windows: myenv\Scripts\activate # On macOS/Linux: source myenv/bin/activate # You should see (myenv) in your terminal prompt

⚠️ Why Use Virtual Environments?

  • Isolation: Each project has its own dependencies
  • No Conflicts: Different projects can use different versions
  • Clean System: Don't pollute global Python installation
  • Reproducibility: Easy to share exact dependencies

Step 3: Install Django

# Install Django (latest version) pip install django # Verify installation django-admin --version # Output: 4.2.7 (or current version) # Install specific version if needed pip install django==4.2.7

πŸ’» Exercise 1.1: Django Environment Setup (15 points)

Complete your first hands-on Django exercise! Set up a complete Django development environment with best practices.

1
Create and activate a virtual environment:
# Create virtual environment python -m venv django_env # Activate virtual environment # Windows: django_env\Scripts\activate # macOS/Linux: # source django_env/bin/activate # Verify activation (you should see (django_env) in prompt)
2
Install Django and verify:
# Install Django pip install django # Check version (should be 4.2.x or higher) django-admin --version
3
Create your first Django project:
# Create project directory mkdir my_first_django_app cd my_first_django_app # Create Django project django-admin startproject mysite . # Project structure should be created
4
Run the development server:
# Apply initial migrations python manage.py migrate # Start development server python manage.py runserver # Visit http://127.0.0.1:8000/ in browser

Learning Outcomes: By completing this exercise, you will have mastered Django environment setup, virtual environments, project creation, and running your first Django application.

πŸ”§ Troubleshooting Tips:

  • Permission Error: On Windows, run terminal as Administrator
  • Virtual env not activating: Check Python installation path
  • Port already in use: Change port with python manage.py runserver 8001
  • Module not found: Ensure virtual environment is activated

πŸ—οΈ Your First Django Project

Create a New Project

# Create project directory mkdir myblog cd myblog # Create Django project django-admin startproject myblog . # Note: The dot (.) creates project in current directory # Project structure created: # myblog/ # β”œβ”€β”€ manage.py # Command-line utility # └── myblog/ # Project package # β”œβ”€β”€ __init__.py # β”œβ”€β”€ settings.py # Project settings # β”œβ”€β”€ urls.py # URL routing # β”œβ”€β”€ asgi.py # ASGI config # └── wsgi.py # WSGI config

Run Development Server

# Start the development server python manage.py runserver # Output: # Starting development server at http://127.0.0.1:8000/ # Quit the server with CTRL-BREAK. # Open browser and visit: http://127.0.0.1:8000/ # You should see Django's welcome page with a rocket! πŸš€

Initial Database Setup

# Apply initial migrations (creates database tables) python manage.py migrate # Output shows migrations being applied: # Operations to perform: # Apply all migrations: admin, auth, contenttypes, sessions # Running migrations: # Applying contenttypes.0001_initial... OK # Applying auth.0001_initial... OK # ... # This creates db.sqlite3 file (your database)

πŸ”„ Django MVT Architecture

MVT Pattern (Model-View-Template)

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ User Browser β”‚ β”‚ (Makes HTTP Request) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ URL Router β”‚ β”‚ (urls.py - Maps URL to View) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ VIEW β”‚ β”‚ (views.py - Business Logic) β”‚ β”‚ - Processes request β”‚ β”‚ - Gets data from Model β”‚ β”‚ - Prepares context for Template β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β–Ό β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ MODEL β”‚ β”‚ TEMPLATE β”‚ β”‚ (models.py) β”‚ β”‚ (HTML files) β”‚ β”‚ - Database β”‚ β”‚ - Presentation β”‚ β”‚ - Data Logic β”‚ β”‚ - User Interfaceβ”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ HTTP Response β”‚ β”‚ (Rendered HTML Page) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Understanding MVT:

  • Model: Defines data structure (database tables)
  • View: Contains business logic (like a controller)
  • Template: Presents data to users (HTML)

Django handles the "Controller" part automatically through its URL routing!

πŸ”„ Why MVT Instead of MVC?

Django's MVT pattern is different from traditional MVC:

  • MVC (Traditional): Model-View-Controller - Controller handles HTTP logic
  • MVT (Django): Model-View-Template - Django handles HTTP logic automatically
  • Django's View: Acts like both Controller (handles requests) and View (business logic)
  • Template: Pure presentation layer (equivalent to MVC's View)

Benefits of MVT Pattern:

  • πŸš€ Faster Development: Less boilerplate code for HTTP handling
  • πŸ”§ Built-in Abstractions: Django manages URL routing, request/response objects
  • πŸ›‘οΈ Security Built-in: Automatic CSRF protection, SQL injection prevention
  • πŸ“ˆ Scalable: Clear separation of concerns while maintaining flexibility
  • 🎯 Batteries Included: Authentication, sessions, admin - all pre-configured

🧠 Exercise 2.1: Django MVT Pattern Deep Dive (20 points)

Test your understanding of Django's architecture! Analyze the MVT pattern by creating a simple questionnaire application.

🎯 Exercise Objective:

Create a complete Django application with Model, View, and Template to understand how MVT components interact.

1
Create the Model (Data Layer):
# question/models.py from django.db import models from django.contrib.auth.models import User class Question(models.Model): """ Model representing a question with choices and correct answer """ text = models.TextField(help_text="The question text") choice_a = models.CharField(max_length=200) choice_b = models.CharField(max_length=200) choice_c = models.CharField(max_length=200) choice_d = models.CharField(max_length=200) correct_answer = models.CharField( max_length=1, choices=[('A', 'A'), ('B', 'B'), ('C', 'C'), ('D', 'D')], help_text="Select the correct choice" ) created_by = models.ForeignKey(User, on_delete=models.CASCADE) created_at = models.DateTimeField(auto_now_add=True) difficulty = models.CharField( max_length=10, choices=[('EASY', 'Easy'), ('MEDIUM', 'Medium'), ('HARD', 'Hard')], default='MEDIUM' ) def __str__(self): return f"Question: {self.text[:50]}..." class Meta: ordering = ['-created_at'] verbose_name = 'Question' verbose_name_plural = 'Questions'
2
Create Views (Business Logic Layer):
# question/views.py from django.shortcuts import render, get_object_or_404 from django.http import JsonResponse from .models import Question def question_list(request): """ View to display all questions - Function-Based View (FBV) """ questions = Question.objects.all() context = { 'questions': questions, 'total_questions': questions.count(), 'page_title': 'Question Bank' } return render(request, 'question/question_list.html', context) def question_detail(request, pk): """ View to display single question with answer """ question = get_object_or_404(Question, pk=pk) context = { 'question': question, 'choices': [ ('A', question.choice_a), ('B', question.choice_b), ('C', question.choice_c), ('D', question.choice_d), ] } return render(request, 'question/question_detail.html', context) # Class-Based View (CBV) example from django.views.generic import ListView, DetailView class QuestionListView(ListView): model = Question template_name = 'question/question_list.html' context_object_name = 'questions' paginate_by = 20 def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['total_questions'] = self.get_queryset().count() context['page_title'] = 'Question Bank (CBV)' return context
3
Create Templates (Presentation Layer):
{% load static %} {% block title %}Question Bank{% endblock %}

Django MVT Demo

{% block content %}{% endblock %}
© 2024 Django Learning
{% extends 'question/base.html' %} {% block title %}{{ page_title }}{% endblock %} {% block content %}

{{ page_title }}

Total Questions: {{ total_questions }}

{% for question in questions %}

{{ forloop.counter }}. {{ question.text }}

Difficulty: {{ question.difficulty }} By: {{ question.created_by.username }} View Answer
{% empty %}

No questions available yet.

Create your first question

{% endfor %} {% endblock %}
4
Configure URL Routing:
# question/urls.py from django.urls import path from . import views app_name = 'question' urlpatterns = [ path('', views.question_list, name='question_list'), path('/', views.question_detail, name='question_detail'), # Alternative CBV routes: # path('cbv/', views.QuestionListView.as_view(), name='question_list_cbv'), ] # myproject/urls.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('questions/', include('question.urls')), path('', include('question.urls')), # Root for demo ]

πŸ§ͺ Testing Your MVT Understanding:

What should you observe when you run this application?

  • Model: Questions stored in database with all field types
  • View: Logic processes HTTP requests and prepares context
  • Template: Dynamically renders HTML using context variables
  • URLs: Clean URL patterns map to specific views
  • Admin: Can manage questions through Django admin interface

πŸ” Analysis Questions:

  1. MVT Flow: Trace how a single question request flows through M→V→T
  2. Data Flow: How does data move from database β†’ view β†’ template?
  3. Separation: Why is business logic separate from presentation?
  4. Reusability: How could you reuse this question model in other apps?
  5. Scalability: How would this design handle 1000+ questions?

Expected Outcome: Complete working question bank demonstrating MVT principles.

πŸ’‘ Learning Takeaways:

  • Models define what data your app works with
  • Views contain the logic that processes requests
  • Templates define how data is presented to users
  • URLs map web addresses to specific views
  • Each component has a clear, separate responsibility

πŸ“± Creating Your First App

What's the Difference: Project vs App?

  • Project: The entire website (e.g., "myblog")
  • App: A specific feature (e.g., "blog", "users", "comments")

One project can have multiple apps. Apps are reusable across projects!

Create an App

# Create a new app called 'blog' python manage.py startapp blog # App structure created: # blog/ # β”œβ”€β”€ __init__.py # β”œβ”€β”€ admin.py # Admin panel configuration # β”œβ”€β”€ apps.py # App configuration # β”œβ”€β”€ models.py # Database models # β”œβ”€β”€ tests.py # Unit tests # β”œβ”€β”€ views.py # View functions # └── migrations/ # Database migrations # └── __init__.py

Register the App

# myblog/settings.py INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'blog', # Add your app here ]

πŸ’Ύ Models - Database Layer

Create Your First Model

# blog/models.py from django.db import models from django.contrib.auth.models import User class Post(models.Model): """Blog post model""" title = models.CharField(max_length=200) slug = models.SlugField(unique=True) author = models.ForeignKey(User, on_delete=models.CASCADE) content = models.TextField() 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'] # Newest first verbose_name = 'Blog Post' verbose_name_plural = 'Blog Posts' def __str__(self): return self.title def get_absolute_url(self): from django.urls import reverse return reverse('post_detail', args=[self.slug])

Common Field Types:

  • CharField - Short text (max_length required)
  • TextField - Long text
  • IntegerField - Integer numbers
  • BooleanField - True/False
  • DateTimeField - Date and time
  • ForeignKey - Relationship to another model
  • EmailField - Email addresses
  • URLField - URLs

πŸ—„οΈ Complete Django Model Field Reference

Django provides 30+ built-in field types covering every data storage need:

πŸ“ Text-Based Fields:

Field Type Description Example Usage
CharField For small to medium strings with max_length name = CharField(max_length=100)
TextField For large amounts of text content = TextField()
SlugField URL-friendly short text (letters, numbers, hyphens) slug = SlugField(unique=True)
UUIDField Universally unique identifiers id = UUIDField(primary_key=True, default=uuid.uuid4)

πŸ”’ Numeric Fields:

Field Type Range Use Case
IntegerField -2.1B to +2.1B Count, quantity, ID numbers
PositiveIntegerField 0 to +2.1B Positive-only quantities
SmallIntegerField -32,768 to +32,767 Smaller ranges, saves space
BigIntegerField -9.2Q to +9.2Q Very large numbers
DecimalField Custom precision Money, scientific calculations
FloatField Double precision Floating point numbers

πŸ“… Date & Time Fields:

# Date and Time Fields from django.db import models class Event(models.Model): # Date only (YYYY-MM-DD) event_date = models.DateField() # Time only (HH:MM:SS) start_time = models.TimeField() # Date and time combined created_at = models.DateTimeField(auto_now_add=True) # Automatically update on save updated_at = models.DateTimeField(auto_now=True) # Optional date (can be null) optional_date = models.DateField(null=True, blank=True) # Date with default published_date = models.DateField(default='2024-01-01')

πŸ”— Relationship Fields:

# Relationship Fields from django.db import models from django.contrib.auth.models import User class Author(models.Model): name = models.CharField(max_length=100) email = models.EmailField(unique=True) class Book(models.Model): title = models.CharField(max_length=200) # One-to-Many relationship (ForeignKey) author = models.ForeignKey( Author, on_delete=models.CASCADE, # What to do when author is deleted related_name='books' # Reverse relationship name ) publication_year = models.IntegerField() class Publisher(models.Model): name = models.CharField(max_length=100) class BookPublisher(models.Model): book = models.ForeignKey(Book, on_delete=models.CASCADE) publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE) published_date = models.DateField() # Composite primary key (book + publisher) class Meta: unique_together = ('book', 'publisher')

🎯 Field Options & Validations:

# Advanced Field Options class Article(models.Model): title = models.CharField( max_length=200, unique=True, # Must be unique across table blank=False, # Required in forms null=False, # Required in database default='Untitled', # Default value help_text='Enter a compelling title', # Form help verbose_name='Article Title' # Admin display name ) slug = models.SlugField( max_length=200, unique=True, blank=True, # Optional in forms null=False # But required in DB (will be auto-generated) ) content = models.TextField( blank=False, help_text='Write your article content here' ) status = models.CharField( max_length=10, choices=[ ('DRAFT', 'Draft'), ('PUBLISHED', 'Published'), ('ARCHIVED', 'Archived') ], default='DRAFT' ) word_count = models.PositiveIntegerField( default=0, editable=False # Read-only in admin ) # Auto-generated fields created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True)

πŸ”— Advanced Model Relationships & Database Design

1️⃣ One-to-One Relationships:

# One-to-One Relationship Example class UserProfile(models.Model): user = models.OneToOneField( User, on_delete=models.CASCADE, primary_key=True ) bio = models.TextField(max_length=500, blank=True) birth_date = models.DateField(null=True, blank=True) website = models.URLField(blank=True) avatar = models.ImageField(upload_to='avatars/', null=True, blank=True) def __str__(self): return f"{self.user.username}'s profile" # Usage: # profile = user.userprofile # Forward relationship # user = profile.user # Reverse relationship

2️⃣ One-to-Many Relationships:

# One-to-Many Relationship (ForeignKey) class Category(models.Model): name = models.CharField(max_length=100) slug = models.SlugField(unique=True) description = models.TextField(blank=True) class Product(models.Model): name = models.CharField(max_length=200) category = models.ForeignKey( Category, on_delete=models.CASCADE, related_name='products' # Access: category.products.all() ) price = models.DecimalField(max_digits=10, decimal_places=2) in_stock = models.BooleanField(default=True) # Usage: # Get all products in a category # products = category.products.all() # Get category of a product # category = product.category

3️⃣ Many-to-Many Relationships:

# Many-to-Many Relationship class Tag(models.Model): name = models.CharField(max_length=50, unique=True) slug = models.SlugField(unique=True) class Article(models.Model): title = models.CharField(max_length=200) content = models.TextField() # Many-to-Many with custom through table tags = models.ManyToManyField( Tag, through='ArticleTag', # Custom intermediate table related_name='articles', blank=True ) published_date = models.DateField() # Custom through model for additional fields class ArticleTag(models.Model): article = models.ForeignKey(Article, on_delete=models.CASCADE) tag = models.ForeignKey(Tag, on_delete=models.CASCADE) added_date = models.DateTimeField(auto_now_add=True) added_by = models.ForeignKey(User, on_delete=models.CASCADE) class Meta: unique_together = ('article', 'tag') # Usage: # Add tags to article # article.tags.add(tag1, tag2) # Get all articles with a tag # articles = tag.articles.all() # Query through model # ArticleTag.objects.filter(tag=tag, article=article)

πŸ” Django ORM: Complete Query Guide

Basic Queries:

# Basic Object Retrieval from .models import Article # Get single object article = Article.objects.get(pk=1) article = Article.objects.get(slug='my-article') # Get multiple objects articles = Article.objects.all() # All articles published = Article.objects.filter(status='PUBLISHED') # Filtered recent = Article.objects.order_by('-published_date')[:5] # Ordered & limited # Count objects total_count = Article.objects.count() published_count = Article.objects.filter(status='PUBLISHED').count() # Check existence has_articles = Article.objects.exists() has_published = Article.objects.filter(status='PUBLISHED').exists()

Advanced Filtering:

# Complex Filtering from django.db.models import Q from datetime import datetime, timedelta # Multiple conditions articles = Article.objects.filter( status='PUBLISHED', published_date__year=2024 ) # OR conditions with Q objects articles = Article.objects.filter( Q(status='PUBLISHED') & Q(published_date__year=2024) ) | Article.objects.filter( Q(status='DRAFT') & Q(author__username='admin') ) # Date range filtering last_week = datetime.now() - timedelta(days=7) recent_articles = Article.objects.filter( published_date__gte=last_week ) # String matching python_articles = Article.objects.filter( title__icontains='python' # Case-insensitive contains ) # Null checking articles_with_tags = Article.objects.exclude(tags__isnull=True) articles_without_tags = Article.objects.filter(tags__isnull=True)

Field Lookups:

Lookup Description Example
exactExact matchtitle__exact='Django'
icontainsCase-insensitive containstitle__icontains='django'
startswithStarts withname__startswith='A'
endswithEnds withname__endswith='z'
gtGreater thanprice__gt=100
gteGreater than or equalprice__gte=100
ltLess thanprice__lt=100
lteLess than or equalprice__lte=100
rangeWithin rangeprice__range=(50, 100)
inIn listid__in=[1, 2, 3]
isnullIs nulldate__isnull=True
yearYear of datedate__year=2024

Complex Queries with Aggregations:

from django.db.models import Count, Sum, Avg, Max, Min # Aggregation queries stats = Article.objects.aggregate( total_articles=Count('id'), published_count=Count('id', filter=Q(status='PUBLISHED')), total_views=Sum('view_count'), avg_word_count=Avg('word_count'), max_word_count=Max('word_count'), min_word_count=Min('word_count') ) # Group by queries author_stats = Article.objects.values('author__username').annotate( article_count=Count('id'), total_views=Sum('view_count') ).order_by('-article_count') # Most popular categories category_stats = Category.objects.annotate( product_count=Count('products'), avg_price=Avg('products__price'), min_price=Min('products__price'), max_price=Max('products__price') ).order_by('-product_count')

Advanced Query Techniques:

# Select related (JOINs) articles_with_authors = Article.objects.select_related('author') # Prefetch related (separate queries for performance) articles_with_tags = Article.objects.prefetch_related('tags') # Raw SQL when needed from django.db import connection cursor = connection.cursor() cursor.execute("SELECT COUNT(*) FROM articles WHERE status = %s", ['PUBLISHED']) count = cursor.fetchone()[0] # Custom managers for reusable queries class PublishedManager(models.Manager): def get_queryset(self): return super().get_queryset().filter(status='PUBLISHED') class Article(models.Model): # ... fields ... objects = models.Manager() # Default manager published = PublishedManager() # Custom manager class Meta: ordering = ['-published_date'] # Usage published_articles = Article.published.all()

βš™οΈ Model Methods & Business Logic

Custom Model Methods:

class Article(models.Model): title = models.CharField(max_length=200) content = models.TextField() status = models.CharField(max_length=10, default='DRAFT') view_count = models.PositiveIntegerField(default=0) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return self.title # Business logic methods def publish(self): """Publish the article""" self.status = 'PUBLISHED' self.save() def unpublish(self): """Unpublish the article""" self.status = 'DRAFT' self.save() def increment_views(self): """Increment view count""" self.view_count += 1 self.save(update_fields=['view_count']) # Computed properties @property def word_count(self): """Calculate word count""" return len(self.content.split()) @property def reading_time(self): """Estimate reading time in minutes""" words_per_minute = 200 return max(1, self.word_count // words_per_minute) @property def excerpt(self, length=100): """Get content excerpt""" if len(self.content) <= length: return self.content return self.content[:length].rstrip() + '...' # Class methods @classmethod def get_popular_articles(cls, limit=10): """Get most viewed articles""" return cls.objects.filter(status='PUBLISHED').order_by('-view_count')[:limit] @classmethod def create_draft(cls, title, content, author): """Factory method for creating drafts""" return cls.objects.create( title=title, content=content, author=author, status='DRAFT' )

Signals & Hooks:

# signals.py from django.db.models.signals import pre_save, post_save from django.dispatch import receiver from .models import Article @receiver(pre_save, sender=Article) def article_pre_save(sender, instance, **kwargs): """Actions before article is saved""" if not instance.slug: # Auto-generate slug from title instance.slug = slugify(instance.title) # Update word count instance.word_count = len(instance.content.split()) @receiver(post_save, sender=Article) def article_post_save(sender, instance, created, **kwargs): """Actions after article is saved""" if created: # Send notification about new article print(f"New article created: {instance.title}") # Update cache, send emails, etc. if instance.status == 'PUBLISHED': # Notify subscribers, update search index, etc. pass # Custom signals from django.dispatch import Signal article_published = Signal() @receiver(article_published) def on_article_published(sender, article, **kwargs): """Custom signal handler""" print(f"Article published: {article.title}")

πŸ“ Exercise 3.1: Complete Blog Application (50 points)

Build a fully functional blog application with advanced features including user authentication, categories, tags, comments, and search functionality.

🎯 Project Requirements:

  1. User Management: Registration, login, profiles
  2. Content Management: Articles with rich text, categories, tags
  3. Comments System: User comments with moderation
  4. Search & Filtering: Full-text search, category/tag filtering
  5. Admin Features: Content moderation, user management
  6. SEO Optimization: Meta tags, sitemaps, RSS feeds

πŸ“‹ Detailed Implementation Steps:

1
Project Setup & Core Models:
# blog/models.py from django.db import models from django.contrib.auth.models import User from django.urls import reverse from taggit.managers import TaggableManager class Category(models.Model): name = models.CharField(max_length=100, unique=True) slug = models.SlugField(unique=True) description = models.TextField(blank=True) color = models.CharField(max_length=7, default='#007bff') # Hex color class Meta: verbose_name_plural = 'Categories' def __str__(self): return self.name def get_absolute_url(self): return reverse('category_detail', kwargs={'slug': self.slug}) class Article(models.Model): STATUS_CHOICES = [ ('DRAFT', 'Draft'), ('PUBLISHED', 'Published'), ('ARCHIVED', 'Archived'), ] title = models.CharField(max_length=200) slug = models.SlugField(unique=True, blank=True) excerpt = models.TextField(max_length=300, blank=True) content = models.TextField() author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='articles') category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, related_name='articles') tags = TaggableManager() status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='DRAFT') featured_image = models.ImageField(upload_to='articles/', null=True, blank=True) # SEO fields meta_title = models.CharField(max_length=60, blank=True) meta_description = models.CharField(max_length=160, blank=True) # Statistics view_count = models.PositiveIntegerField(default=0) like_count = models.PositiveIntegerField(default=0) # Timestamps created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) published_at = models.DateTimeField(null=True, blank=True) objects = models.Manager() # Default manager class Meta: ordering = ['-published_at', '-created_at'] def __str__(self): return self.title def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.title) if self.status == 'PUBLISHED' and not self.published_at: self.published_at = timezone.now() super().save(*args, **kwargs) def get_absolute_url(self): return reverse('article_detail', kwargs={'slug': self.slug}) @property def word_count(self): return len(self.content.split()) @property def reading_time(self): words_per_minute = 200 return max(1, self.word_count // words_per_minute) def increment_views(self): self.view_count = models.F('view_count') + 1 self.save(update_fields=['view_count']) class Comment(models.Model): article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='comments') author = models.ForeignKey(User, on_delete=models.CASCADE) content = models.TextField() created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) # Moderation is_approved = models.BooleanField(default=True) is_spam = models.BooleanField(default=False) class Meta: ordering = ['created_at'] def __str__(self): return f'Comment by {self.author.username} on {self.article.title}'
2
Views Implementation:
# blog/views.py from django.shortcuts import render, get_object_or_404, redirect from django.contrib.auth.decorators import login_required from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView from django.contrib import messages from django.db.models import Q, Count from django.core.paginator import Paginator from .models import Article, Category, Comment from .forms import ArticleForm, CommentForm class ArticleListView(ListView): model = Article template_name = 'blog/article_list.html' context_object_name = 'articles' paginate_by = 12 def get_queryset(self): queryset = Article.objects.filter(status='PUBLISHED') # Category filtering category_slug = self.request.GET.get('category') if category_slug: queryset = queryset.filter(category__slug=category_slug) # Tag filtering tag = self.request.GET.get('tag') if tag: queryset = queryset.filter(tags__name__in=[tag]) # Search functionality query = self.request.GET.get('q') if query: queryset = queryset.filter( Q(title__icontains=query) | Q(content__icontains=query) | Q(excerpt__icontains=query) ) return queryset.distinct() def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['categories'] = Category.objects.annotate( article_count=Count('articles') ).filter(article_count__gt=0) context['featured_articles'] = Article.objects.filter( status='PUBLISHED' ).order_by('-view_count')[:3] return context class ArticleDetailView(DetailView): model = Article template_name = 'blog/article_detail.html' context_object_name = 'article' def get_queryset(self): return Article.objects.filter(status='PUBLISHED') def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['comments'] = self.object.comments.filter(is_approved=True) context['comment_form'] = CommentForm() context['related_articles'] = Article.objects.filter( Q(category=self.object.category) | Q(tags__in=self.object.tags.all()) ).exclude(id=self.object.id).distinct()[:4] # Increment view count self.object.increment_views() return context @login_required def add_comment(request, slug): article = get_object_or_404(Article, slug=slug, status='PUBLISHED') if request.method == 'POST': form = CommentForm(request.POST) if form.is_valid(): comment = form.save(commit=False) comment.article = article comment.author = request.user comment.save() messages.success(request, 'Your comment has been added!') return redirect('article_detail', slug=slug) return redirect('article_detail', slug=slug) class ArticleCreateView(LoginRequiredMixin, CreateView): model = Article form_class = ArticleForm template_name = 'blog/article_form.html' def form_valid(self, form): form.instance.author = self.request.user messages.success(self.request, 'Article created successfully!') return super().form_valid(form) # Additional views for update, delete, user dashboard, etc.

This comprehensive exercise will teach you:

  • Complex model relationships and database design
  • Advanced Django ORM queries and aggregations
  • User authentication and authorization
  • Form handling and validation
  • Template inheritance and reusable components
  • Admin interface customization
  • Search functionality and filtering
  • SEO optimization techniques
  • Performance optimization
  • Testing and debugging strategies

πŸŽ‰ Upon Completion You'll Have:

  • A production-ready blog application
  • Understanding of real-world Django development
  • Portfolio project for job applications
  • Foundation for building complex web applications

Create and Apply Migrations

# Create migration files (tells Django what changed) python manage.py makemigrations # Output: # Migrations for 'blog': # blog/migrations/0001_initial.py # - Create model Post # Apply migrations (creates actual database tables) python manage.py migrate # Output: # Operations to perform: # Apply all migrations: admin, auth, blog, contenttypes, sessions # Running migrations: # Applying blog.0001_initial... OK

πŸ‘οΈ Views - Logic Layer

Function-Based Views

# blog/views.py from django.shortcuts import render, get_object_or_404 from django.http import HttpResponse from .models import Post def post_list(request): """Display all published posts""" posts = Post.objects.filter(published=True) context = { 'posts': posts, 'title': 'All Posts' } return render(request, 'blog/post_list.html', context) def post_detail(request, slug): """Display single post""" post = get_object_or_404(Post, slug=slug, published=True) context = { 'post': post, 'title': post.title } return render(request, 'blog/post_detail.html', context) def home(request): """Homepage view""" return HttpResponse("Welcome to My Blog!")

Class-Based Views

# blog/views.py from django.views.generic import ListView, DetailView from .models import Post class PostListView(ListView): model = Post template_name = 'blog/post_list.html' context_object_name = 'posts' paginate_by = 10 def get_queryset(self): return Post.objects.filter(published=True) class PostDetailView(DetailView): model = Post template_name = 'blog/post_detail.html' context_object_name = 'post' def get_queryset(self): return Post.objects.filter(published=True)

πŸ”— URL Routing

App URLs

# blog/urls.py (create this file) 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'), ]

Project URLs

# myblog/urls.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('blog/', include('blog.urls')), # Include blog URLs path('', include('blog.urls')), # Root URL ]

🎨 Templates - Presentation Layer

Create Templates Directory

# Create directory structure: # blog/ # └── templates/ # └── blog/ # β”œβ”€β”€ base.html # β”œβ”€β”€ post_list.html # └── post_detail.html

Base Template

{% block title %}My Blog{% endblock %}

My Blog

{% block content %} {% endblock %}

© 2024 My Blog

Post List Template

{% extends 'blog/base.html' %} {% block title %}{{ title }} - My Blog{% endblock %} {% block content %}

{{ title }}

{% if posts %} {% for post in posts %}

{{ post.title }}

By {{ post.author.username }} on {{ post.created_at|date:"F d, Y" }}

{{ post.content|truncatewords:50 }}

{% endfor %} {% else %}

No posts yet.

{% endif %} {% endblock %}

Post Detail Template

{% extends 'blog/base.html' %} {% block title %}{{ post.title }} - My Blog{% endblock %} {% block content %}

{{ post.title }}

By {{ post.author.username }} on {{ post.created_at|date:"F d, Y" }}

{{ post.content|linebreaks }}
← Back to all posts {% endblock %}

βš™οΈ Django Admin Panel

Create Superuser

# Create admin account python manage.py createsuperuser # Enter details: # Username: admin # Email: admin@example.com # Password: (enter secure password) # Password (again): (confirm password) # Superuser created successfully!

Register Models in Admin

# blog/admin.py from django.contrib import admin from .models import Post @admin.register(Post) class PostAdmin(admin.ModelAdmin): list_display = ['title', 'author', 'created_at', 'published'] list_filter = ['published', 'created_at'] search_fields = ['title', 'content'] prepopulated_fields = {'slug': ('title',)} date_hierarchy = 'created_at' ordering = ['-created_at'] fieldsets = ( ('Post Information', { 'fields': ('title', 'slug', 'author', 'content') }), ('Status', { 'fields': ('published',) }), )

Access Admin Panel

# Start server python manage.py runserver # Visit: http://127.0.0.1:8000/admin/ # Login with superuser credentials # You can now manage posts through the admin interface!

πŸ“ Forms

Create a Form

# blog/forms.py (create this file) from django import forms from .models import Post class PostForm(forms.ModelForm): class Meta: model = Post fields = ['title', 'slug', 'content', 'published'] widgets = { 'content': forms.Textarea(attrs={'rows': 10}), } def clean_title(self): title = self.cleaned_data.get('title') if len(title) < 5: raise forms.ValidationError('Title must be at least 5 characters') return title

Use Form in View

# blog/views.py from django.shortcuts import render, redirect from .forms import PostForm def create_post(request): if request.method == 'POST': form = PostForm(request.POST) if form.is_valid(): post = form.save(commit=False) post.author = request.user post.save() return redirect('blog:post_detail', slug=post.slug) else: form = PostForm() return render(request, 'blog/create_post.html', {'form': form})

πŸ” Authentication

Login View

# blog/views.py from django.contrib.auth import authenticate, login, logout from django.shortcuts import render, redirect def user_login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') user = authenticate(request, username=username, password=password) if user is not None: login(request, user) return redirect('blog:post_list') else: return render(request, 'blog/login.html', { 'error': 'Invalid credentials' }) return render(request, 'blog/login.html') def user_logout(request): logout(request) return redirect('blog:post_list')

Protect Views

# blog/views.py from django.contrib.auth.decorators import login_required @login_required def create_post(request): # Only logged-in users can access this view # ... pass

πŸ’‘ Best Practices

Django Best Practices:

  • Use Virtual Environments: Always isolate project dependencies
  • Keep SECRET_KEY Secret: Never commit to version control
  • Use Environment Variables: For sensitive configuration
  • Write Tests: Test your models, views, and forms
  • Use Django ORM: Avoid raw SQL queries
  • Follow DRY Principle: Don't Repeat Yourself
  • Use Class-Based Views: For complex views
  • Organize Apps Properly: Keep apps focused and reusable
  • Use Django's Built-in Features: Don't reinvent the wheel
  • Document Your Code: Write clear docstrings

πŸš€ Deployment Basics

Prepare for Production

# settings.py changes for production # Turn off debug mode DEBUG = False # Set allowed hosts ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com'] # Use environment variables import os SECRET_KEY = os.environ.get('SECRET_KEY') # Configure static files STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') # Use production database (PostgreSQL recommended) DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.environ.get('DB_NAME'), 'USER': os.environ.get('DB_USER'), 'PASSWORD': os.environ.get('DB_PASSWORD'), 'HOST': os.environ.get('DB_HOST'), 'PORT': '5432', } }

Collect Static Files

# Collect all static files to STATIC_ROOT python manage.py collectstatic # This gathers all static files from all apps # into a single directory for serving in production

πŸ› οΈ Useful Django Commands

# Create new project django-admin startproject projectname # Create new app python manage.py startapp appname # Run development server python manage.py runserver # Create migrations python manage.py makemigrations # Apply migrations python manage.py migrate # Create superuser python manage.py createsuperuser # Open Django shell python manage.py shell # Run tests python manage.py test # Collect static files python manage.py collectstatic # Check for problems python manage.py check

πŸ“š Learning Resources

Official Resources

  • Django Documentation
  • Django Tutorial
  • Django Girls Tutorial
  • Django REST Framework Docs

Video Tutorials

  • Corey Schafer Django Series
  • Traversy Media Django Crash Course
  • freeCodeCamp Django Tutorial
  • Tech With Tim Django Series

Books

  • Django for Beginners
  • Two Scoops of Django
  • Django for APIs
  • Django for Professionals

Practice Projects

  • Blog Application
  • Todo List App
  • E-commerce Site
  • Social Media Clone

πŸ’Ό Career Opportunities

Django Developer Roles:

  • Junior Django Developer: $50,000 - $70,000/year
  • Django Developer: $70,000 - $100,000/year
  • Senior Django Developer: $100,000 - $140,000/year
  • Django Architect: $120,000 - $160,000+/year

High demand for Django developers in web development, fintech, and data-driven applications!

πŸš€ Start Building with Django!

Create powerful web applications with Python's most popular framework

πŸ“– Related Topics