Django Fundamentals and Project Setup
Set up Django projects. Learn directory structures, settings configs, manage.py CLI command mappings, and development execution.
Downloaded from PrepIQ (https://prepiq.online)
Q1. What is Django and what are its key features and advantages?
Django is a high-level Python web framework that follows the MVT (Model-View-Template) architecture. It includes built-in admin panel, ORM, authentication system, and security features, making it ideal for rapid development of scalable web applications.
| Feature | Benefit | Use Case |
|---|---|---|
| MVT Architecture | Clear separation of concerns | Organized project structure |
| ORM (Object-Relational Mapping) | Write queries in Python | Database abstraction |
| Admin Panel | Ready-to-use CRUD interface | Quick data management |
| Authentication | Built-in user management | Secure login systems |
| Form Handling | Automatic validation | Safe data processing |
// Install Django
pip install django
// Create new project
django-admin startproject myproject
cd myproject
// Create new app
python manage.py startapp myapp
// Project structure
myproject/
├── manage.py # CLI tool
├── myproject/
│ ├── __init__.py
│ ├── settings.py # Configuration
│ ├── urls.py # URL routing
│ ├── asgi.py # ASGI config
│ └── wsgi.py # WSGI config
└── myapp/
├── migrations/ # Database migrations
├── models.py # Database models
├── views.py # Business logic
├── urls.py # App URLs
├── templates/ # HTML templates
├── static/ # CSS, JS, images
├── forms.py # Form definitions
├── admin.py # Admin configuration
└── tests.py # Unit tests
// Key Django Features
// 1. MVT Architecture - Clean code organization
// 2. ORM - No SQL needed
// 3. Admin Panel - Auto-generated CRUD
// 4. Authentication - User management built-in
// 5. Form Validation - Automatic validation
// 6. Security - CSRF protection, SQL injection prevention
// 7. Testing Framework - Unit and integration tests
// 8. Middleware - Request/response processing
// 9. Signals - Decoupled app communication
// 10. Migrations - Database schema management
// Run development server
python manage.py runserver
// Access at http://localhost:8000/
Q2. Explain Django MVT (Model-View-Template) architecture and how it differs from MVC.
MVT (Model-View-Template) is Django's architectural pattern where Model manages data, View handles logic, and Template generates HTML. Unlike MVC, Django's View is the Controller and Template is the View, making MVT a variation optimized for Django's design philosophy.
| Component | MVT (Django) | MVC (Rails) | Responsibility |
|---|---|---|---|
| Model | Database layer | Database layer | Data & business logic |
| View/Controller | View = Business logic | Controller = Logic | Process requests |
| Template/View | Template = UI | View = UI | Render HTML |
// DJANGO MVT FLOW
// 1. URL Routes to View
// 2. View retrieves/processes data from Model
// 3. View renders Template with data
// 4. Template displays HTML
// models.py (Model Layer)
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
// views.py (View Layer - Business Logic)
from django.shortcuts import render, get_object_or_404
from .models import Product
def product_list(request):
# Get data from Model
products = Product.objects.all()
# Process data
total_price = sum(p.price for p in products)
# Pass to Template
context = {'products': products, 'total': total_price}
return render(request, 'product_list.html', context)
def product_detail(request, pk):
product = get_object_or_404(Product, pk=pk)
return render(request, 'product_detail.html', {'product': product})
// urls.py (URL Routing)
from django.urls import path
from . import views
urlpatterns = [
path('products/', views.product_list, name='product_list'),
path('products/<int:pk>/', views.product_detail, name='product_detail'),
]
// product_list.html (Template Layer - UI)
{% for product in products %}
<div class='product'>
<h2>{{ product.name }}</h2>
<p>Price: ${{ product.price }}</p>
<a href='{% url "product_detail" product.pk %}'>
View Details
</a>
</div>
{% endfor %}
<p>Total: ${{ total }}</p>
// MVT Request-Response Cycle
// 1. User requests /products/
// 2. Django matches URL pattern
// 3. View retrieves Products from Model
// 4. View passes data to Template
// 5. Template renders HTML
// 6. HTML sent back to user
// Advantages of MVT
// 1. Clear separation of concerns
// 2. Reusable components
// 3. Easy to test each layer
// 4. Rapid development
// 5. Secure by default
Q3. What are Django Models and how do you use the ORM for database operations?
Django Models are Python classes that define database table structure. The ORM (Object-Relational Mapping) abstracts SQL, allowing you to interact with database using Python code instead of writing raw SQL queries.
// Define Models
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=100)
description = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['name']
verbose_name_plural = 'Categories'
def __str__(self):
return self.name
class Product(models.Model):
CATEGORY_CHOICES = [
('electronics', 'Electronics'),
('clothing', 'Clothing'),
('books', 'Books'),
]
name = models.CharField(max_length=200)
description = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='products')
quantity = models.IntegerField(default=0)
is_active = models.BooleanField(default=True)
created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-created_at']
indexes = [
models.Index(fields=['name', 'category']),
]
def __str__(self):
return self.name
// ORM Query Operations
from myapp.models import Product, Category
// CREATE
product = Product.objects.create(
name='Laptop',
price=999.99,
category_id=1,
quantity=50
)
// READ - Get single object
product = Product.objects.get(id=1) # Raises DoesNotExist if not found
product = Product.objects.filter(name='Laptop').first() # Returns None if not found
// READ - Get all objects
all_products = Product.objects.all()
// READ - Filter
active_products = Product.objects.filter(is_active=True)
expensive = Product.objects.filter(price__gte=1000)
cheap = Product.objects.filter(price__lt=100)
// READ - Complex queries
from django.db.models import Q
products = Product.objects.filter(
Q(name__icontains='phone') | Q(name__icontains='tablet'),
is_active=True
)
// UPDATE
product = Product.objects.get(id=1)
product.price = 1299.99
product.save()
// Bulk update
Product.objects.filter(category_id=1).update(price=F('price') * 1.1)
// DELETE
product.delete()
Product.objects.filter(quantity=0).delete()
// Aggregation
from django.db.models import Sum, Count, Avg
total_revenue = Product.objects.aggregate(Sum('price'))
product_count = Product.objects.count()
avg_price = Product.objects.aggregate(Avg('price'))
// Grouping
from django.db.models import Sum
category_stats = Product.objects.values('category').annotate(
total_products=Count('id'),
avg_price=Avg('price')
)
// Ordering
products_asc = Product.objects.order_by('name')
products_desc = Product.objects.order_by('-created_at')
// Slicing
first_10 = Product.objects.all()[:10]
page_2 = Product.objects.all()[10:20]
// Relationships
# Get products in a category
category = Category.objects.get(id=1)
category_products = category.products.all()
# Get category of a product
product = Product.objects.get(id=1)
category = product.category
Q4. What are Django Views? Explain Function-Based Views (FBV) vs Class-Based Views (CBV).
Views are Python functions/classes that receive requests and return responses. FBV are simple functions for straightforward logic, while CBV use classes with methods for complex reusable logic. CBV provides inheritance, mixins, and built-in HTTP method handling.
// FUNCTION-BASED VIEWS (FBV)
from django.shortcuts import render, redirect
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from .models import Product
from .forms import ProductForm
# Simple view
@require_http_methods(['GET', 'POST'])
def product_list(request):
if request.method == 'POST':
form = ProductForm(request.POST)
if form.is_valid():
form.save()
return redirect('product_list')
else:
form = ProductForm()
products = Product.objects.all()
return render(request, 'products/list.html', {
'products': products,
'form': form
})
# Detail view with URL parameter
def product_detail(request, product_id):
try:
product = Product.objects.get(id=product_id)
return render(request, 'products/detail.html', {'product': product})
except Product.DoesNotExist:
return render(request, '404.html', status=404)
// CLASS-BASED VIEWS (CBV)
from django.views import View
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
# Generic view for listing
class ProductListView(ListView):
model = Product
template_name = 'products/list.html'
context_object_name = 'products'
paginate_by = 10
def get_queryset(self):
return Product.objects.filter(is_active=True)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['total_products'] = self.get_queryset().count()
return context
# Generic view for detail
class ProductDetailView(DetailView):
model = Product
template_name = 'products/detail.html'
context_object_name = 'product'
pk_url_kwarg = 'product_id'
# Generic view for creation
class ProductCreateView(LoginRequiredMixin, CreateView):
model = Product
form_class = ProductForm
template_name = 'products/form.html'
success_url = reverse_lazy('product_list')
def form_valid(self, form):
form.instance.created_by = self.request.user
return super().form_valid(form)
# Generic view for update
class ProductUpdateView(UpdateView):
model = Product
form_class = ProductForm
template_name = 'products/form.html'
pk_url_kwarg = 'product_id'
def get_success_url(self):
return reverse('product_detail', args=[self.object.id])
// Custom Class-Based View
class ProductAPIView(View):
def get(self, request, product_id=None):
if product_id:
product = Product.objects.get(id=product_id)
return JsonResponse({
'id': product.id,
'name': product.name,
'price': str(product.price)
})
else:
products = list(Product.objects.values('id', 'name', 'price'))
return JsonResponse({'products': products})
def post(self, request):
# Handle POST
data = request.POST
product = Product.objects.create(**data)
return JsonResponse({'id': product.id})
// urls.py
from django.urls import path
from . import views
urlpatterns = [
# FBV routes
path('products/', views.product_list, name='product_list'),
path('products/<int:product_id>/', views.product_detail, name='product_detail'),
# CBV routes
path('api/products/', views.ProductListView.as_view(), name='product_list_cbv'),
path('api/products/<int:pk>/', views.ProductDetailView.as_view(), name='product_detail_cbv'),
path('api/products/create/', views.ProductCreateView.as_view(), name='product_create'),
]
// FBV vs CBV Comparison
// FBV Advantages:
// - Simple and straightforward
// - Direct control over logic
// - Easy for small views
// - Good for beginners
// CBV Advantages:
// - Reusable code
// - Inheritance and mixins
// - DRY principle
// - Built-in generic views
// - HTTP method separation
// - Better for complex applications
Q5. What are Django Templates and template syntax? How do you use template tags and filters?
Django Templates are HTML files with embedded Python logic using template tags and filters. Use {{ }} for variables, {% %} for logic, and filters to transform data. Template inheritance enables code reusability and maintains consistent site structure.
// base.html (Parent Template)
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Site{% endblock %}</title>
{% load static %}
<link rel='stylesheet' href='{% static "css/style.css" %}'>
</head>
<body>
<header>
<nav>
<a href='{% url "home" %}'>Home</a>
<a href='{% url "products" %}'>Products</a>
</nav>
</header>
<main>
{% block content %}
{% endblock %}
</main>
<footer>
<p>© 2024 My Site</p>
</footer>
</body>
</html>
// product_list.html (Child Template)
{% extends 'base.html' %}
{% load static %}
{% block title %}Products - My Site{% endblock %}
{% block content %}
<h1>Products</h1>
<!-- Variables -->
<p>Total Products: {{ total_count }}</p>
<!-- Conditionals -->
{% if products %}
<div class='products'>
<!-- Loops -->
{% for product in products %}
<div class='product-card'>
<h2>{{ product.name }}</h2>
<!-- Filters -->
<p>Price: ${{ product.price|floatformat:2 }}</p>
<p>Category: {{ product.category.name|upper }}</p>
<p>Description: {{ product.description|truncatewords:20 }}</p>
<!-- Dates -->
<p>Created: {{ product.created_at|date:"F d, Y" }}</p>
<!-- Conditionals inside loop -->
{% if product.quantity > 0 %}
<span class='in-stock'>In Stock ({{ product.quantity }})</span>
{% else %}
<span class='out-of-stock'>Out of Stock</span>
{% endif %}
<!-- URL reversal -->
<a href='{% url "product_detail" product.id %}'>
View Details
</a>
</div>
{% empty %}
<p>No products available</p>
{% endfor %}
</div>
{% else %}
<p>No products found</p>
{% endif %}
<!-- Pagination -->
{% if is_paginated %}
<div class='pagination'>
{% if page_obj.has_previous %}
<a href='?page=1'>First</a>
<a href='?page={{ page_obj.previous_page_number }}'>Previous</a>
{% endif %}
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
{% if page_obj.has_next %}
<a href='?page={{ page_obj.next_page_number }}'>Next</a>
<a href='?page={{ page_obj.paginator.num_pages }}'>Last</a>
{% endif %}
</div>
{% endif %}
{% endblock %}
// Template Tags and Filters
{{ variable }} // Display variable
{{ variable|filter }} // Apply filter
{{ variable|filter:"arg" }} // Filter with argument
{{ value|default:"N/A" }} // Default value
{{ text|length }} // String length
{{ text|truncatewords:10 }} // Truncate
{{ date|date:"F d, Y" }} // Format date
{{ price|floatformat:2 }} // Format decimal
{{ text|lower|upper }} // Chaining filters
// Common Template Tags
{% if condition %}...{% endif %} // Conditional
{% for item in items %}...{% endfor %} // Loop
{% for item in items %}...{% empty %} // Empty fallback
{% with var=value %}...{% endwith %} // Variable assignment
{% include "snippet.html" %} // Include template
{% load static %} // Load app tags
{% static "path/file.css" %} // Static files
{% url "view_name" args %} // URL reversal
{% csrf_token %} // CSRF protection
// Custom Filters and Tags
# In myapp/templatetags/custom_filters.py
from django import template
register = template.Library()
@register.filter
def multiply(value, factor):
return value * factor
@register.tag
def show_total(parser, token):
# Custom tag logic
pass
// In template
{% load custom_filters %}
{{ price|multiply:2 }} // Use custom filter
Q6. What is Django Admin Panel and how do you customize it?
Django Admin is an auto-generated CRUD interface for managing database records. Register models in admin.py to expose them. Customize with ModelAdmin to control display, filtering, search, and actions without writing additional code.
// admin.py - Basic Setup
from django.contrib import admin
from .models import Product, Category
// Register model with default admin
admin.site.register(Product)
admin.site.register(Category)
// Customized Admin
from django.contrib.admin import ModelAdmin, register
from django.utils.html import format_html
@register(Product)
class ProductAdmin(ModelAdmin):
# Display fields in list view
list_display = ['id', 'name', 'category', 'price', 'quantity', 'status_display', 'created_at']
# Add search
search_fields = ['name', 'description', 'category__name']
# Add filters
list_filter = ['category', 'is_active', 'created_at']
# Fields to edit inline
readonly_fields = ['created_at', 'updated_at', 'color_preview']
# Organize edit form
fieldsets = (
('Product Information', {
'fields': ('name', 'description', 'category')
}),
('Pricing & Inventory', {
'fields': ('price', 'quantity')
}),
('Status & Metadata', {
'fields': ('is_active', 'created_by', 'created_at', 'updated_at'),
'classes': ('collapse',) # Collapsible section
}),
)
# Inline editing for related objects
class ProductImageInline(admin.TabularInline):
model = ProductImage
extra = 1 # How many empty forms to show
inlines = [ProductImageInline]
# Pagination
list_per_page = 50
# Sort by default
ordering = ['-created_at']
# Custom methods for display
def status_display(self, obj):
color = 'green' if obj.is_active else 'red'
status = 'Active' if obj.is_active else 'Inactive'
return format_html(
'<span style="color: {};">{}</span>',
color, status
)
status_display.short_description = 'Status'
def color_preview(self, obj):
return format_html(
'<div style="width:50px;height:50px;background-color:{}"></div>',
obj.color_code
)
color_preview.short_description = 'Color Preview'
# Custom actions
def make_active(self, request, queryset):
updated = queryset.update(is_active=True)
self.message_user(request, f'{updated} products activated')
make_active.short_description = 'Mark selected as active'
def make_inactive(self, request, queryset):
queryset.update(is_active=False)
make_inactive.short_description = 'Mark selected as inactive'
actions = ['make_active', 'make_inactive']
# Override save method
def save_model(self, request, obj, form, change):
if not change: # New object
obj.created_by = request.user
super().save_model(request, obj, form, change)
# Custom queryset for non-superusers
def get_queryset(self, request):
qs = super().get_queryset(request)
if not request.user.is_superuser:
qs = qs.filter(created_by=request.user)
return qs
// Admin site customization
from django.contrib import admin
admin.site.site_header = 'My Store Administration'
admin.site.site_title = 'My Store Admin'
admin.site.index_title = 'Welcome to Admin Panel'
// Access admin
// 1. Create superuser
python manage.py createsuperuser
// 2. Navigate to http://localhost:8000/admin/
// Common ModelAdmin options
// list_display - Columns in list
// search_fields - Searchable fields
// list_filter - Sidebar filters
// readonly_fields - Non-editable fields
// fieldsets - Form organization
// inlines - Related object editing
// list_per_page - Pagination
// ordering - Default sort
// actions - Bulk actions
Q7. What are Django Forms and how do you handle form validation and processing?
Django Forms provide form handling, validation, and rendering. Use ModelForm to automatically generate forms from models. Forms handle data validation, CSRF protection, and error messages without writing additional code.
// forms.py
from django import forms
from .models import Product, Review
// Model Form - Auto-generated from Model
class ProductForm(forms.ModelForm):
# Override field properties
description = forms.CharField(
widget=forms.Textarea(attrs={
'rows': 5,
'placeholder': 'Enter product description'
}),
required=True,
help_text='Minimum 50 characters required'
)
price = forms.DecimalField(
max_digits=10,
decimal_places=2,
min_value=0.01,
error_messages={
'invalid': 'Enter a valid price',
'min_value': 'Price must be greater than 0'
}
)
class Meta:
model = Product
fields = ['name', 'description', 'price', 'category', 'quantity']
labels = {
'name': 'Product Name',
'price': 'Product Price (USD)'
}
widgets = {
'name': forms.TextInput(attrs={'class': 'form-control'}),
'category': forms.Select(attrs={'class': 'form-control'}),
'quantity': forms.NumberInput(attrs={'class': 'form-control', 'min': 0}),
}
# Custom validation for single field
def clean_name(self):
name = self.cleaned_data.get('name')
if len(name) < 3:
raise forms.ValidationError('Name must be at least 3 characters')
return name
# Custom validation across fields
def clean(self):
cleaned_data = super().clean()
price = cleaned_data.get('price')
quantity = cleaned_data.get('quantity')
if price and quantity:
if quantity == 0 and price > 0:
raise forms.ValidationError(
'Cannot set price for out-of-stock product'
)
return cleaned_data
// Regular Form - Manual field definition
class ReviewForm(forms.Form):
RATING_CHOICES = [(i, str(i)) for i in range(1, 6)]
rating = forms.ChoiceField(
choices=RATING_CHOICES,
widget=forms.RadioSelect,
required=True
)
title = forms.CharField(
max_length=200,
widget=forms.TextInput(attrs={'class': 'form-control'})
)
review = forms.CharField(
widget=forms.Textarea(attrs={
'class': 'form-control',
'rows': 5
})
)
def clean_review(self):
review = self.cleaned_data.get('review')
if len(review) < 10:
raise forms.ValidationError('Review must be at least 10 characters')
return review
// Using Forms in Views
from django.shortcuts import render, redirect
def create_product(request):
if request.method == 'POST':
form = ProductForm(request.POST, request.FILES) # request.FILES for file uploads
if form.is_valid(): # Runs all validations
product = form.save(commit=False)
product.created_by = request.user
product.save()
return redirect('product_detail', pk=product.id)
# If not valid, form re-rendered with errors
else:
form = ProductForm()
return render(request, 'products/form.html', {'form': form})
// Templates
<form method='post' enctype='multipart/form-data'>
{% csrf_token %}
<!-- Render entire form -->
{{ form.as_p }} <!-- Paragraphs -->
{{ form.as_table }} <!-- Table -->
{{ form.as_ul }} <!-- List -->
<!-- Or render fields individually -->
<div class='form-group'>
{{ form.name.label_tag }}
{{ form.name }}
{% if form.name.errors %}
<div class='error'>
{{ form.name.errors }}
</div>
{% endif %}
</div>
<button type='submit'>Submit</button>
</form>
// Form Validation Flow
// 1. form.is_valid() called
// 2. Run field-level clean_<field>()
// 3. Run form-level clean()
// 4. Populate cleaned_data
// 5. Return True/False
// Common Validations
min_length, max_length
min_value, max_value
regex pattern
required
unique
Email validator
URL validator
Custom validators
Q8. What is Django Middleware and how do you create custom middleware?
Middleware is a set of hooks/filters that process requests and responses globally. Built-in middleware handles security, sessions, and authentication. Create custom middleware for logging, timing, authentication checks, or modifying requests/responses.
// Middleware Execution Order
// Request: Top to Bottom
// Response: Bottom to Top
// settings.py - Middleware configuration
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'myapp.middleware.CustomLoggingMiddleware', # Custom
'myapp.middleware.TimingMiddleware', # Custom
]
// middleware.py - Custom Middleware
import time
import logging
from django.utils.deprecation import MiddlewareMixin
logger = logging.getLogger(__name__)
// Method 1: Class-based middleware
class CustomLoggingMiddleware(MiddlewareMixin):
# Called for every request
def process_request(self, request):
logger.info(f'Request: {request.method} {request.path}')
logger.info(f'User: {request.user}')
# Return None to continue, or Response to short-circuit
return None
# Called after view processes request (if view returns response)
def process_view(self, request, view_func, view_args, view_kwargs):
logger.info(f'View: {view_func.__name__}')
return None
# Called after response is generated
def process_response(self, request, response):
logger.info(f'Response Status: {response.status_code}')
return response
# Called if view raises exception
def process_exception(self, request, exception):
logger.error(f'Exception: {exception}')
return None
// Timing Middleware
class TimingMiddleware(MiddlewareMixin):
def process_request(self, request):
request._start_time = time.time()
return None
def process_response(self, request, response):
if hasattr(request, '_start_time'):
duration = time.time() - request._start_time
logger.info(f'{request.path} took {duration:.2f} seconds')
response['X-Process-Time'] = str(duration)
return response
// Authentication Middleware
class AuthenticationCheckMiddleware(MiddlewareMixin):
def process_request(self, request):
# Skip for public pages
public_urls = ['/login/', '/register/', '/about/']
if request.path not in public_urls:
if not request.user.is_authenticated:
# Redirect to login or return 403
from django.shortcuts import redirect
return redirect('login')
return None
// IP Blocking Middleware
class IPBlockMiddleware(MiddlewareMixin):
BLOCKED_IPS = ['192.168.1.100', '10.0.0.1']
def process_request(self, request):
client_ip = self.get_client_ip(request)
if client_ip in self.BLOCKED_IPS:
from django.http import HttpResponse
return HttpResponse('Access Denied', status=403)
return None
def get_client_ip(self, request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = request.META.get('REMOTE_ADDR')
return ip
// Middleware Execution Flow
/*
Request Flow:
1. process_request (top to bottom)
2. process_view
3. View processes request
4. process_response (bottom to top)
Exception Flow:
1. process_exception called
2. Custom error handling
3. Return error response
Example Order:
SecurityMiddleware.process_request
SessionMiddleware.process_request
CsrfMiddleware.process_request
CustomMiddleware.process_request
[View Processing]
CustomMiddleware.process_response
CsrfMiddleware.process_response
SessionMiddleware.process_response
SecurityMiddleware.process_response
*/
// Common Use Cases
// 1. Request/response logging
// 2. Performance monitoring
// 3. Authentication checking
// 4. IP blocking
// 5. Header modification
// 6. Request timing
// 7. Error tracking
// 8. Rate limiting
Q9. What are Django Migrations and how do you manage database schema changes?
Migrations are version control for database schema. Django automatically detects model changes and generates migration files. Use makemigrations to create migrations and migrate to apply them. Manage schema changes safely without data loss.
// Migration Workflow
// Step 1: Create migration files
python manage.py makemigrations
// Detects changes in models.py
// Generates migration files in migrations/ folder
// Step 2: Review migrations
cat myapp/migrations/0001_initial.py
// Step 3: Apply migrations
python manage.py migrate
// Runs all unapplied migrations
// Updates database schema
// Step 4: Verify
python manage.py showmigrations
// Shows which migrations are applied
// Example Migration File
# myapp/migrations/0001_initial.py
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name='Product',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200)),
('price', models.DecimalField(decimal_places=2, max_digits=10)),
('created_at', models.DateTimeField(auto_now_add=True)),
],
),
]
// Migration for Field Change
# myapp/migrations/0002_add_quantity.py
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='product',
name='quantity',
field=models.IntegerField(default=0),
),
]
// Common Migration Operations
// Add field
migrations.AddField(
model_name='product',
name='description',
field=models.TextField(default=''),
)
// Remove field
migrations.RemoveField(
model_name='product',
name='old_field',
)
// Rename field
migrations.RenameField(
model_name='product',
old_name='price',
new_name='selling_price',
)
// Alter field
migrations.AlterField(
model_name='product',
name='price',
field=models.DecimalField(decimal_places=3, max_digits=10),
)
// Create model
migrations.CreateModel(
name='Category',
fields=[
('id', models.BigAutoField(primary_key=True)),
('name', models.CharField(max_length=100)),
],
)
// Delete model
migrations.DeleteModel(
name='OldModel',
)
// Data migration - modify existing data
python manage.py makemigrations --empty myapp --name populate_data
# Then edit the migration file
from django.db import migrations
def populate_categories(apps, schema_editor):
Product = apps.get_model('myapp', 'Product')
for product in Product.objects.all():
# Modify data
pass
class Migration(migrations.Migration):
dependencies = [
('myapp', '0002_previous_migration'),
]
operations = [
migrations.RunPython(populate_categories),
]
// Useful Commands
python manage.py makemigrations # Create migration files
python manage.py makemigrations myapp # Only for myapp
python manage.py migrate # Apply all migrations
python manage.py migrate myapp # Apply only myapp migrations
python manage.py migrate myapp 0002 # Migrate to specific version
python manage.py migrate myapp zero # Revert all migrations
python manage.py showmigrations # Show migration status
python manage.py sqlmigrate myapp 0001 # Show SQL for migration
python manage.py makemigrations --dry-run # Preview changes
// Best Practices
// 1. Run makemigrations after model changes
// 2. Review generated migrations before applying
// 3. Test migrations on development first
// 4. Never modify applied migrations
// 5. Create new migration for changes
// 6. Use data migrations for data transformation
// 7. Version control all migration files
// 8. Keep migrations atomic (single purpose)
Q10. How do you manage Django settings for different environments (dev, staging, prod)?
Use environment-specific settings files and environment variables for configuration. Create settings/base.py for common config and settings/dev.py, settings/prod.py for environment-specific overrides. Use python-decouple to load environment variables securely.
// Project Structure
myproject/
├── manage.py
├── .env # Environment variables (gitignored)
├── .env.example # Example (version controlled)
└── myproject/
├── __init__.py
└── settings/
├── __init__.py
├── base.py # Common settings
├── dev.py # Development
├── staging.py # Staging
└── prod.py # Production
// settings/base.py (Common Settings)
from pathlib import Path
import os
from decouple import config
BASE_DIR = Path(__file__).resolve().parent.parent.parent
SECRET_KEY = config('SECRET_KEY')
DEBUG = config('DEBUG', default=False, cast=bool)
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='localhost', cast=lambda v: [s.strip() for s in v.split(',')])
// Database
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': config('DB_NAME'),
'USER': config('DB_USER'),
'PASSWORD': config('DB_PASSWORD'),
'HOST': config('DB_HOST'),
'PORT': config('DB_PORT', default='5432'),
}
}
// Installed Apps
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'corsheaders',
'myapp',
]
// Middleware
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
]
// Logging
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {'class': 'logging.StreamHandler'},
'file': {'class': 'logging.FileHandler', 'filename': 'debug.log'},
},
'loggers': {'django': {'handlers': ['console'], 'level': 'INFO'}},
}
// settings/dev.py (Development)
from .base import *
DEBUG = True
ALLOWED_HOSTS = ['*']
// SQLite for development
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
// Disable security checks in dev
SECURE_SSL_REDIRECT = False
SESSION_COOKIE_SECURE = False
// Django Debug Toolbar
INSTALLED_APPS += ['debug_toolbar']
MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware']
INTERNAL_IPS = ['127.0.0.1']
// Email backend for testing
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
// settings/prod.py (Production)
from .base import *
DEBUG = False
ALLOWED_HOSTS = config('ALLOWED_HOSTS').split(',')
// Security settings
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'
// Static files with CDN
STATIC_URL = config('STATIC_URL')
STATIC_ROOT = BASE_DIR / 'staticfiles'
STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
// Email backend
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = config('EMAIL_HOST')
EMAIL_PORT = config('EMAIL_PORT', cast=int)
EMAIL_USE_TLS = True
EMAIL_HOST_USER = config('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD')
// .env file
SECRET_KEY=your-secret-key-here
DEBUG=False
ALLOWED_HOSTS=example.com,www.example.com
DB_NAME=proddb
DB_USER=dbuser
DB_PASSWORD=securepassword
DB_HOST=prod-db-server.example.com
DB_PORT=5432
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_HOST_USER=your-email@gmail.com
EMAIL_HOST_PASSWORD=app-password
// manage.py modification
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', os.getenv('DJANGO_SETTINGS_MODULE', 'myproject.settings.dev'))
// Run with different settings
python manage.py runserver --settings=myproject.settings.dev
export DJANGO_SETTINGS_MODULE=myproject.settings.prod
python manage.py migrate
// Best Practices
// 1. Keep secrets in environment variables
// 2. Use python-decouple for config
// 3. Never commit .env file
// 4. Provide .env.example
// 5. Use separate settings for each environment
// 6. Document all required environment variables
// 7. Use strong SECRET_KEY in production
// 8. Enable security middleware in production
Django Fundamentals and Project Setup
Set up Django projects. Learn directory structures, settings configs, manage.py CLI command mappings, and development execution.
What is Django and what are its key features and advantages?
Django is a high-level Python web framework that follows the MVT (Model-View-Template) architecture. It includ...
Explain Django MVT (Model-View-Template) architecture and how it differs from MVC.
MVT (Model-View-Template) is Django's architectural pattern where Model manages data, View handles logic, and...
What are Django Models and how do you use the ORM for database operations?
Django Models are Python classes that define database table structure. The ORM (Object-Relational Mapping) abs...
What are Django Views? Explain Function-Based Views (FBV) vs Class-Based Views (CBV).
Views are Python functions/classes that receive requests and return responses. FBV are simple functions for st...
What are Django Templates and template syntax? How do you use template tags and filters?
Django Templates are HTML files with embedded Python logic using template tags and filters. Use {{ }} for vari...
What is Django Admin Panel and how do you customize it?
Django Admin is an auto-generated CRUD interface for managing database records. Register models in admin.py to...
What are Django Forms and how do you handle form validation and processing?
Django Forms provide form handling, validation, and rendering. Use ModelForm to automatically generate forms f...
What is Django Middleware and how do you create custom middleware?
Middleware is a set of hooks/filters that process requests and responses globally. Built-in middleware handles...
What are Django Migrations and how do you manage database schema changes?
Migrations are version control for database schema. Django automatically detects model changes and generates m...
How do you manage Django settings for different environments (dev, staging, prod)?
Use environment-specific settings files and environment variables for configuration. Create settings/base.py f...