Django Application Overview
Build comprehensive Django web applications with proper model design, view hierarchies, database operations, user authentication, and admin functionality following Django conventions and best practices.
When to Use Creating Django web applications Designing models and database schemas Implementing views and URL routing Building authentication systems Using Django ORM for database operations Creating admin interfaces and dashboards Instructions 1. Django Project Setup django-admin startproject myproject cd myproject python manage.py startapp users python manage.py startapp products
- Model Design with ORM
users/models.py
from django.contrib.auth.models import AbstractUser from django.db import models from django.contrib.auth import get_user_model
class CustomUser(AbstractUser): ROLE_CHOICES = [ ('admin', 'Administrator'), ('user', 'Regular User'), ] profile_picture = models.ImageField(upload_to='profiles/', null=True) role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='user') created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-created_at']
indexes = [
models.Index(fields=['email']),
models.Index(fields=['role']),
]
def __str__(self):
return self.email
products/models.py
User = get_user_model()
class Product(models.Model): STATUS_CHOICES = [ ('draft', 'Draft'), ('published', 'Published'), ]
title = models.CharField(max_length=200, db_index=True)
slug = models.SlugField(unique=True)
description = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
stock = models.PositiveIntegerField(default=0)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='products')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-created_at']
unique_together = ['slug', 'owner']
def __str__(self):
return self.title
class ProductReview(models.Model): product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='reviews') author = models.ForeignKey(User, on_delete=models.CASCADE) rating = models.IntegerField(choices=[(i, i) for i in range(1, 6)]) comment = models.TextField() created_at = models.DateTimeField(auto_now_add=True)
class Meta:
unique_together = ['product', 'author']
- Views with Class-Based and Function-Based Approaches
products/views.py
from django.views import View from django.views.generic import ListView, DetailView, CreateView from django.contrib.auth.mixins import LoginRequiredMixin from django.shortcuts import render, redirect, get_object_or_404 from django.http import JsonResponse from django.db.models import Q, Count, Avg from rest_framework import viewsets, status from rest_framework.response import Response from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated
from .models import Product, ProductReview from .serializers import ProductSerializer
Class-based view with authentication
class ProductListView(LoginRequiredMixin, ListView): model = Product template_name = 'products/list.html' context_object_name = 'products' paginate_by = 20
def get_queryset(self):
queryset = Product.objects.filter(status='published')
# Search and filter
search = self.request.GET.get('q')
if search:
queryset = queryset.filter(
Q(title__icontains=search) | Q(description__icontains=search)
)
# Price range filter
min_price = self.request.GET.get('min_price')
max_price = self.request.GET.get('max_price')
if min_price:
queryset = queryset.filter(price__gte=min_price)
if max_price:
queryset = queryset.filter(price__lte=max_price)
return queryset.annotate(
review_count=Count('reviews'),
avg_rating=Avg('reviews__rating')
).order_by('-created_at')
REST API ViewSet
class ProductViewSet(viewsets.ModelViewSet): permission_classes = [IsAuthenticated] serializer_class = ProductSerializer queryset = Product.objects.all()
def get_queryset(self):
return Product.objects.filter(owner=self.request.user)
@action(detail=True, methods=['post'])
def add_review(self, request, pk=None):
product = self.get_object()
serializer = ProductReviewSerializer(data=request.data)
if serializer.is_valid():
serializer.save(product=product, author=request.user)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@action(detail=True, methods=['get'])
def reviews(self, request, pk=None):
product = self.get_object()
reviews = product.reviews.all()
serializer = ProductReviewSerializer(reviews, many=True)
return Response(serializer.data)
- Authentication and Permissions
users/views.py
from django.contrib.auth import authenticate, login, logout from django.views.decorators.http import require_http_methods from django.views.decorators.csrf import csrf_protect from rest_framework.authtoken.models import Token from rest_framework.permissions import BasePermission
class IsOwner(BasePermission): def has_object_permission(self, request, view, obj): return obj.owner == request.user
@require_http_methods(['POST']) @csrf_protect def login_view(request): email = request.POST.get('email') password = request.POST.get('password') user = authenticate(request, username=email, password=password)
if user is not None:
login(request, user)
token, created = Token.objects.get_or_create(user=user)
return JsonResponse({
'success': True,
'token': token.key,
'user_id': user.id
})
return JsonResponse({'error': 'Invalid credentials'}, status=401)
@require_http_methods(['POST']) def logout_view(request): logout(request) return JsonResponse({'success': True})
- Database Queries and Optimization
products/queries.py
from django.db.models import Q, Count, Avg, F, Case, When, Value from django.db.models.functions import Coalesce from .models import Product, ProductReview
Optimized queries with select_related and prefetch_related
def get_product_details(product_id): return Product.objects.select_related('owner').prefetch_related( 'reviews__author' ).get(id=product_id)
Aggregation queries
def get_top_products(): return Product.objects.annotate( review_count=Count('reviews'), avg_rating=Avg('reviews__rating'), total_reviews=Count('reviews', distinct=True) ).filter(review_count__gt=0).order_by('-avg_rating')[:10]
Complex filtering
def search_products(query, category=None, min_price=None, max_price=None): queryset = Product.objects.filter( Q(title__icontains=query) | Q(description__icontains=query) )
if category:
queryset = queryset.filter(category=category)
if min_price:
queryset = queryset.filter(price__gte=min_price)
if max_price:
queryset = queryset.filter(price__lte=max_price)
return queryset.select_related('owner')
Bulk operations
def bulk_update_stock(updates): products_to_update = [] for product_id, new_stock in updates.items(): product = Product.objects.get(id=product_id) product.stock = new_stock products_to_update.append(product)
Product.objects.bulk_update(products_to_update, ['stock'])
- URL Routing
myproject/urls.py
from django.contrib import admin from django.urls import path, include from rest_framework.routers import DefaultRouter from rest_framework.authtoken.views import obtain_auth_token from products.views import ProductViewSet
router = DefaultRouter() router.register(r'products', ProductViewSet)
urlpatterns = [ path('admin/', admin.site.urls), path('api/', include(router.urls)), path('api-token-auth/', obtain_auth_token), ]
- Admin Interface Customization
products/admin.py
from django.contrib import admin from .models import Product, ProductReview
@admin.register(Product) class ProductAdmin(admin.ModelAdmin): list_display = ['title', 'price', 'stock', 'status', 'owner', 'created_at'] list_filter = ['status', 'created_at', 'owner'] search_fields = ['title', 'description'] readonly_fields = ['created_at', 'updated_at'] fieldsets = ( ('Basic Info', { 'fields': ('title', 'slug', 'owner') }), ('Details', { 'fields': ('description', 'price', 'stock', 'status') }), ('Metadata', { 'fields': ('created_at', 'updated_at'), 'classes': ('collapse',) }), )
def save_model(self, request, obj, form, change):
if not change:
obj.owner = request.user
super().save_model(request, obj, form, change)
@admin.register(ProductReview) class ProductReviewAdmin(admin.ModelAdmin): list_display = ['product', 'author', 'rating', 'created_at'] list_filter = ['rating', 'created_at'] readonly_fields = ['created_at']
Best Practices ✅ DO Use models for database operations Implement proper indexes on frequently queried fields Use select_related and prefetch_related for query optimization Implement authentication and permissions Use Django Forms for form validation Cache expensive queries Use management commands for batch operations Implement logging for debugging Use middleware for cross-cutting concerns Validate user input ❌ DON'T Use raw SQL without ORM N+1 query problems without optimization Store secrets in code Trust user input directly Override init in models unnecessarily Make synchronous heavy operations in views Use inheritance models unless necessary Expose stack traces in production Complete Example
settings.py
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'rest_framework', 'users', 'products' ]
AUTH_USER_MODEL = 'users.CustomUser'
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.TokenAuthentication', ], 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', ] }