Django Samples

Django web framework examples including models, views, templates, Django REST Framework, and modern Django patterns

Key Facts

Category
Web Frameworks
Items
3
Format Families
sample

Sample Overview

Django web framework examples including models, views, templates, Django REST Framework, and modern Django patterns This sample set belongs to Web Frameworks and can be used to test related workflows inside Elysia Tools.

💻 Django Hello World python

🟢 simple

Basic Django project setup and Hello World application with models, views, and templates

⏱️ 25 min 🏷️ django, python, web framework, mvc
Prerequisites: Python basics, HTML/CSS basics, MVC concepts
# Django Hello World Examples

# 1. Project Structure
"""
myproject/
├── myproject/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
│   └── asgi.py
├── hello/
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── models.py
│   ├── views.py
│   ├── urls.py
│   └── templates/
│       └── hello/
│           ├── base.html
│           ├── index.html
│           └── greeting.html
├── manage.py
└── requirements.txt
"""

# 2. requirements.txt
"""
Django>=4.2.0
"""

# 3. Create Django Project and App
"""
# Commands to set up the project:
django-admin startproject myproject
cd myproject
python manage.py startapp hello
"""

# 4. Project Settings (myproject/settings.py)
import os
from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-your-secret-key-here'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ['localhost', '127.0.0.1']

# Application definition
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'hello',  # Our custom app
]

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',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'myproject.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'myproject.wsgi.application'

# Database
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

# Password validation
AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Internationalization
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True

# Static files (CSS, JavaScript, Images)
STATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / 'static']

# Default primary key field type
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

# 5. Main URLs (myproject/urls.py)
from django.contrib import admin
from django.urls import path, include
from django.http import HttpResponse

def hello_world(request):
    return HttpResponse("Hello, World! This is the main Django project.")

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', hello_world, name='hello_world'),
    path('hello/', include('hello.urls')),
]

# 6. App Configuration (hello/apps.py)
from django.apps import AppConfig

class HelloConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'hello'

# 7. Models (hello/models.py)
from django.db import models
from django.contrib.auth.models import User

class Greeting(models.Model):
    name = models.CharField(max_length=100)
    message = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    is_active = models.BooleanField(default=True)
    user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)

    def __str__(self):
        return f"{self.name} - {self.message[:50]}"

    class Meta:
        ordering = ['-created_at']

class Visitor(models.Model):
    ip_address = models.GenericIPAddressField()
    user_agent = models.TextField(blank=True)
    visit_count = models.PositiveIntegerField(default=1)
    first_visit = models.DateTimeField(auto_now_add=True)
    last_visit = models.DateTimeField(auto_now=True)

    def __str__(self):
        return f"Visitor from {self.ip_address} ({self.visit_count} visits)"

# 8. Views (hello/views.py)
from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponse, JsonResponse
from django.views import View
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.utils import timezone
from django.contrib import messages
from .models import Greeting, Visitor
from .forms import GreetingForm

# Function-based views
def hello_world(request):
    """Simple Hello World view"""
    return HttpResponse("Hello, World! Welcome to Django!")

def hello_name(request, name):
    """Hello World with name parameter"""
    context = {
        'name': name,
        'current_time': timezone.now(),
    }
    return render(request, 'hello/greeting.html', context)

def greeting_form(request):
    """Greeting form view"""
    if request.method == 'POST':
        name = request.POST.get('name', 'World')
        message = request.POST.get('message', 'Hello!')
        Greeting.objects.create(name=name, message=message)
        messages.success(request, f'Greeting from {name} created successfully!')
        return redirect('hello:greeting_list')

    return render(request, 'hello/greeting_form.html')

# Class-based views
class HelloWorldView(View):
    """Class-based Hello World view"""
    def get(self, request):
        return HttpResponse("Hello, World! This is a class-based view.")

class PersonalizedHelloView(View):
    """Class-based view with name parameter"""
    def get(self, request, name):
        context = {'name': name}
        return render(request, 'hello/personalized_hello.html', context)

class GreetingListView(ListView):
    """List all greetings"""
    model = Greeting
    template_name = 'hello/greeting_list.html'
    context_object_name = 'greetings'
    paginate_by = 10

class GreetingDetailView(DetailView):
    """Detail view for a single greeting"""
    model = Greeting
    template_name = 'hello/greeting_detail.html'
    context_object_name = 'greeting'

class GreetingCreateView(LoginRequiredMixin, CreateView):
    """Create a new greeting"""
    model = Greeting
    form_class = GreetingForm
    template_name = 'hello/greeting_form.html'
    success_url = reverse_lazy('hello:greeting_list')

    def form_valid(self, form):
        form.instance.user = self.request.user
        messages.success(self.request, 'Greeting created successfully!')
        return super().form_valid(form)

class GreetingUpdateView(LoginRequiredMixin, UpdateView):
    """Update an existing greeting"""
    model = Greeting
    form_class = GreetingForm
    template_name = 'hello/greeting_form.html'
    success_url = reverse_lazy('hello:greeting_list')

    def form_valid(self, form):
        messages.success(self.request, 'Greeting updated successfully!')
        return super().form_valid(form)

class GreetingDeleteView(LoginRequiredMixin, DeleteView):
    """Delete a greeting"""
    model = Greeting
    template_name = 'hello/greeting_confirm_delete.html'
    success_url = reverse_lazy('hello:greeting_list')

    def delete(self, request, *args, **kwargs):
        messages.success(request, 'Greeting deleted successfully!')
        return super().delete(request, *args, **kwargs)

# API Views
def api_greetings(request):
    """API endpoint to get all greetings"""
    greetings = Greeting.objects.filter(is_active=True)
    data = [
        {
            'id': g.id,
            'name': g.name,
            'message': g.message,
            'created_at': g.created_at.isoformat(),
            'user': g.user.username if g.user else None
        }
        for g in greetings
    ]
    return JsonResponse({'greetings': data})

def api_hello(request):
    """API Hello World endpoint"""
    data = {
        'message': 'Hello, World!',
        'framework': 'Django',
        'version': '4.2+',
        'timestamp': timezone.now().isoformat()
    }
    return JsonResponse(data)

# 9. Forms (hello/forms.py)
from django import forms
from .models import Greeting

class GreetingForm(forms.ModelForm):
    class Meta:
        model = Greeting
        fields = ['name', 'message', 'is_active']
        widgets = {
            'name': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': 'Enter your name'
            }),
            'message': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 4,
                'placeholder': 'Enter your message'
            }),
            'is_active': forms.CheckboxInput(attrs={
                'class': 'form-check-input'
            })
        }

    def clean_name(self):
        name = self.cleaned_data.get('name')
        if len(name.strip()) < 2:
            raise forms.ValidationError('Name must be at least 2 characters long.')
        return name.strip()

    def clean_message(self):
        message = self.cleaned_data.get('message')
        if len(message.strip()) < 5:
            raise forms.ValidationError('Message must be at least 5 characters long.')
        return message.strip()

# 10. App URLs (hello/urls.py)
from django.urls import path
from . import views

app_name = 'hello'

urlpatterns = [
    # Function-based views
    path('world/', views.hello_world, name='hello_world'),
    path('world/<str:name>/', views.hello_name, name='hello_name'),
    path('form/', views.greeting_form, name='greeting_form'),

    # Class-based views
    path('class/', views.HelloWorldView.as_view(), name='hello_class'),
    path('class/<str:name>/', views.PersonalizedHelloView.as_view(), name='personalized_hello'),

    # CRUD views
    path('greetings/', views.GreetingListView.as_view(), name='greeting_list'),
    path('greetings/<int:pk>/', views.GreetingDetailView.as_view(), name='greeting_detail'),
    path('greetings/create/', views.GreetingCreateView.as_view(), name='greeting_create'),
    path('greetings/<int:pk>/edit/', views.GreetingUpdateView.as_view(), name='greeting_update'),
    path('greetings/<int:pk>/delete/', views.GreetingDeleteView.as_view(), name='greeting_delete'),

    # API endpoints
    path('api/hello/', views.api_hello, name='api_hello'),
    path('api/greetings/', views.api_greetings, name='api_greetings'),
]

# 11. Base Template (hello/templates/hello/base.html)
"""
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}Django Hello World{% endblock %}</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <style>
        body {
            background-color: #f8f9fa;
        }
        .navbar-brand {
            font-weight: bold;
        }
        .footer {
            background-color: #343a40;
            color: white;
            padding: 20px 0;
            margin-top: 50px;
        }
    </style>
    {% block extra_css %}{% endblock %}
</head>
<body>
    <!-- Navigation -->
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <div class="container">
            <a class="navbar-brand" href="{% url 'hello:hello_world' %}">Django Demo</a>

            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
                <span class="navbar-toggler-icon"></span>
            </button>

            <div class="collapse navbar-collapse" id="navbarNav">
                <ul class="navbar-nav me-auto">
                    <li class="nav-item">
                        <a class="nav-link" href="{% url 'hello:hello_world' %}">Hello World</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{% url 'hello:greeting_list' %}">Greetings</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{% url 'hello:greeting_create' %}">Add Greeting</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{% url 'hello:api_hello' %}">API</a>
                    </li>
                </ul>

                <ul class="navbar-nav">
                    {% if user.is_authenticated %}
                        <li class="nav-item">
                            <a class="nav-link" href="{% url 'admin:index' %}">Admin</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link" href="#">Welcome, {{ user.username }}</a>
                        </li>
                    {% else %}
                        <li class="nav-item">
                            <a class="nav-link" href="{% url 'admin:login' %}">Login</a>
                        </li>
                    {% endif %}
                </ul>
            </div>
        </div>
    </nav>

    <!-- Messages -->
    {% if messages %}
        <div class="container mt-3">
            {% for message in messages %}
                <div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
                    {{ message }}
                    <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
                </div>
            {% endfor %}
        </div>
    {% endif %}

    <!-- Main Content -->
    <main class="container my-4">
        {% block content %}{% endblock %}
    </main>

    <!-- Footer -->
    <footer class="footer">
        <div class="container text-center">
            <p>&copy; 2024 Django Hello World Demo. Built with Django {{ VERSION }}.</p>
        </div>
    </footer>

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
    {% block extra_js %}{% endblock %}
</body>
</html>

# 12. Index Template (hello/templates/hello/index.html)
{% extends 'hello/base.html' %}

{% block title %}Django Hello World{% endblock %}

{% block content %}
<div class="row">
    <div class="col-md-8 mx-auto">
        <div class="card text-center">
            <div class="card-header bg-primary text-white">
                <h1>🌍 Hello, World!</h1>
            </div>
            <div class="card-body">
                <p class="lead">Welcome to your Django application!</p>
                <p>This is a simple demonstration of Django's capabilities:</p>

                <div class="row mt-4">
                    <div class="col-md-4">
                        <div class="card h-100">
                            <div class="card-body">
                                <h5 class="card-title">⚡ Fast</h5>
                                <p class="card-text">Django helps you build web applications quickly and efficiently.</p>
                            </div>
                        </div>
                    </div>
                    <div class="col-md-4">
                        <div class="card h-100">
                            <div class="card-body">
                                <h5 class="card-title">🔒 Secure</h5>
                                <p class="card-text">Built-in security features protect against common vulnerabilities.</p>
                            </div>
                        </div>
                    </div>
                    <div class="col-md-4">
                        <div class="card h-100">
                            <div class="card-body">
                                <h5 class="card-title">📈 Scalable</h5>
                                <p class="card-text">Django scales to handle millions of requests per day.</p>
                            </div>
                        </div>
                    </div>
                </div>

                <div class="mt-4">
                    <a href="{% url 'hello:greeting_list' %}" class="btn btn-primary btn-lg me-2">View Greetings</a>
                    <a href="{% url 'hello:greeting_create' %}" class="btn btn-success btn-lg">Add Greeting</a>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

# 13. Greeting Template (hello/templates/hello/greeting.html)
{% extends 'hello/base.html' %}

{% block title %}Hello, {{ name }}!{% endblock %}

{% block content %}
<div class="row">
    <div class="col-md-6 mx-auto">
        <div class="card">
            <div class="card-header bg-success text-white">
                <h2>👋 Hello, {{ name }}!</h2>
            </div>
            <div class="card-body">
                <p class="lead">Welcome to the Django application!</p>
                <p><strong>Current Time:</strong> {{ current_time|date:"F j, Y, g:i a" }}</p>

                <div class="mt-3">
                    <a href="{% url 'hello:hello_world' %}" class="btn btn-secondary">Back to Home</a>
                    <a href="{% url 'hello:greeting_create' %}" class="btn btn-primary">Create a Greeting</a>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}
"""

# 14. Run the Application
"""
# Commands to run the application:
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
python manage.py runserver

# Visit these URLs:
# http://127.0.0.1:8000/ - Main Hello World
# http://127.0.0.1:8000/hello/world/ - App Hello World
# http://127.0.0.1:8000/hello/world/John/ - Personalized greeting
# http://127.0.0.1:8000/admin/ - Django admin
# http://127.0.0.1:8000/hello/greetings/ - Greeting list
# http://127.0.0.1:8000/hello/api/hello/ - API endpoint
"""

💻 Django REST Framework python

🟡 intermediate ⭐⭐⭐⭐

Advanced Django REST API examples including serializers, viewsets, authentication, and API design patterns

⏱️ 50 min 🏷️ django, rest framework, api, serializers, viewsets
Prerequisites: Django basics, REST API concepts, Authentication
# Django REST Framework Examples

# 1. requirements.txt
"""
Django>=4.2.0
djangorestframework>=3.14.0
django-cors-headers>=4.0.0
django-filter>=23.0
Pillow>=10.0.0
python-decouple>=3.8
"""

# 2. Project Settings (settings.py additions)
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'rest_framework.authtoken',
    'django_filters',
    'corsheaders',
    'api',  # Our API app
]

# REST Framework Configuration
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticatedOrReadOnly',
    ],
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 20,
    'DEFAULT_FILTER_BACKENDS': [
        'django_filters.rest_framework.DjangoFilterBackend',
        'rest_framework.filters.SearchFilter',
        'rest_framework.filters.OrderingFilter',
    ],
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ],
    'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
}

# CORS Configuration
CORS_ALLOWED_ORIGINS = [
    "http://localhost:3000",
    "http://127.0.0.1:3000",
]

# 3. Models (api/models.py)
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
from django.utils.text import slugify
import uuid

class Category(models.Model):
    name = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(max_length=100, unique=True, blank=True)
    description = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.name)
        super().save(*args, **kwargs)

    def __str__(self):
        return self.name

class Product(models.Model):
    STATUS_CHOICES = [
        ('draft', 'Draft'),
        ('published', 'Published'),
        ('archived', 'Archived'),
    ]

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=200)
    slug = models.SlugField(max_length=200, unique=True, blank=True)
    description = models.TextField()
    price = models.DecimalField(max_digits=10, decimal_places=2)
    image = models.ImageField(upload_to='products/', blank=True, null=True)
    category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='products')
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='draft')
    is_featured = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='products')

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.name)
        super().save(*args, **kwargs)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('api:product-detail', kwargs={'slug': self.slug})

class Review(models.Model):
    RATING_CHOICES = [(i, str(i)) for i in range(1, 6)]

    product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='reviews')
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    rating = models.IntegerField(choices=RATING_CHOICES)
    title = models.CharField(max_length=100)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    is_approved = models.BooleanField(default=False)

    class Meta:
        unique_together = ['product', 'user']

    def __str__(self):
        return f"{self.product.name} - {self.user.username} ({self.rating}/5)"

class Tag(models.Model):
    name = models.CharField(max_length=50, unique=True)
    products = models.ManyToManyField(Product, related_name='tags', blank=True)

    def __str__(self):
        return self.name

# 4. Serializers (api/serializers.py)
from rest_framework import serializers
from django.contrib.auth.models import User
from .models import Product, Category, Review, Tag

class CategorySerializer(serializers.ModelSerializer):
    products_count = serializers.IntegerField(source='products.count', read_only=True)

    class Meta:
        model = Category
        fields = ['id', 'name', 'slug', 'description', 'products_count', 'created_at']

class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = ['id', 'name']

class ReviewSerializer(serializers.ModelSerializer):
    user = serializers.StringRelatedField(read_only=True)

    class Meta:
        model = Review
        fields = ['id', 'user', 'rating', 'title', 'content', 'created_at', 'is_approved']
        read_only_fields = ['user', 'created_at', 'is_approved']

class ProductListSerializer(serializers.ModelSerializer):
    category_name = serializers.CharField(source='category.name', read_only=True)
    average_rating = serializers.SerializerMethodField()
    reviews_count = serializers.SerializerMethodField()

    class Meta:
        model = Product
        fields = [
            'id', 'name', 'slug', 'description', 'price', 'image',
            'category_name', 'status', 'is_featured', 'created_at',
            'average_rating', 'reviews_count'
        ]

    def get_average_rating(self, obj):
        approved_reviews = obj.reviews.filter(is_approved=True)
        if approved_reviews.exists():
            return round(sum(review.rating for review in approved_reviews) / approved_reviews.count(), 1)
        return 0

    def get_reviews_count(self, obj):
        return obj.reviews.filter(is_approved=True).count()

class ProductDetailSerializer(serializers.ModelSerializer):
    category = CategorySerializer(read_only=True)
    reviews = ReviewSerializer(many=True, read_only=True)
    tags = TagSerializer(many=True, read_only=True)
    created_by = serializers.StringRelatedField(read_only=True)
    average_rating = serializers.SerializerMethodField()

    class Meta:
        model = Product
        fields = [
            'id', 'name', 'slug', 'description', 'price', 'image',
            'category', 'status', 'is_featured', 'created_at', 'updated_at',
            'created_by', 'reviews', 'tags', 'average_rating'
        ]

    def get_average_rating(self, obj):
        approved_reviews = obj.reviews.filter(is_approved=True)
        if approved_reviews.exists():
            return round(sum(review.rating for review in approved_reviews) / approved_reviews.count(), 1)
        return 0

class ProductCreateUpdateSerializer(serializers.ModelSerializer):
    tags = serializers.ListField(
        child=serializers.CharField(max_length=50),
        write_only=True,
        required=False
    )

    class Meta:
        model = Product
        fields = [
            'name', 'slug', 'description', 'price', 'image',
            'category', 'status', 'is_featured', 'tags'
        ]

    def create(self, validated_data):
        tags_data = validated_data.pop('tags', [])
        product = Product.objects.create(**validated_data)

        for tag_name in tags_data:
            tag, created = Tag.objects.get_or_create(name=tag_name.lower())
            product.tags.add(tag)

        return product

    def update(self, instance, validated_data):
        tags_data = validated_data.pop('tags', None)

        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()

        if tags_data is not None:
            instance.tags.clear()
            for tag_name in tags_data:
                tag, created = Tag.objects.get_or_create(name=tag_name.lower())
                instance.tags.add(tag)

        return instance

class UserSerializer(serializers.ModelSerializer):
    products_count = serializers.IntegerField(source='products.count', read_only=True)

    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'first_name', 'last_name', 'products_count']
        read_only_fields = ['id']

# 5. Views (api/views.py)
from rest_framework import viewsets, status, permissions, filters
from rest_framework.decorators import action, api_view, permission_classes
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination
from django_filters.rest_framework import DjangoFilterBackend
from django.shortcuts import get_object_or_404
from django.db.models import Avg, Count
from django.contrib.auth.models import User
from .models import Product, Category, Review, Tag
from .serializers import (
    ProductListSerializer, ProductDetailSerializer, ProductCreateUpdateSerializer,
    CategorySerializer, ReviewSerializer, UserSerializer, TagSerializer
)

class StandardResultsSetPagination(PageNumberPagination):
    page_size = 10
    page_size_query_param = 'page_size'
    max_page_size = 100

class ProductViewSet(viewsets.ModelViewSet):
    """
    ViewSet for viewing and editing products.
    Provides list, create, retrieve, update, destroy actions.
    """
    queryset = Product.objects.all()
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ['category', 'status', 'is_featured']
    search_fields = ['name', 'description']
    ordering_fields = ['name', 'price', 'created_at']
    ordering = ['-created_at']
    pagination_class = StandardResultsSetPagination

    def get_serializer_class(self):
        if self.action == 'list':
            return ProductListSerializer
        elif self.action in ['create', 'update', 'partial_update']:
            return ProductCreateUpdateSerializer
        return ProductDetailSerializer

    def get_permissions(self):
        if self.action in ['create', 'update', 'partial_update', 'destroy']:
            permission_classes = [permissions.IsAuthenticated]
        else:
            permission_classes = [permissions.IsAuthenticatedOrReadOnly]
        return [permission() for permission in permission_classes]

    def perform_create(self, serializer):
        serializer.save(created_by=self.request.user)

    @action(detail=True, methods=['post'], permission_classes=[permissions.IsAuthenticated])
    def add_review(self, request, pk=None):
        product = self.get_object()

        # Check if user already reviewed
        if Review.objects.filter(product=product, user=request.user).exists():
            return Response(
                {'error': 'You have already reviewed this product.'},
                status=status.HTTP_400_BAD_REQUEST
            )

        serializer = ReviewSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(product=product, user=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.filter(is_approved=True)
        serializer = ReviewSerializer(reviews, many=True)
        return Response(serializer.data)

    @action(detail=False, methods=['get'])
    def featured(self, request):
        """Get all featured products"""
        featured_products = Product.objects.filter(is_featured=True, status='published')
        page = self.paginate_queryset(featured_products)
        serializer = ProductListSerializer(page, many=True)
        return self.get_paginated_response(serializer.data)

    @action(detail=False, methods=['get'])
    def by_category(self, request):
        """Filter products by category slug"""
        category_slug = request.query_params.get('slug')
        if not category_slug:
            return Response(
                {'error': 'Category slug parameter is required.'},
                status=status.HTTP_400_BAD_REQUEST
            )

        category = get_object_or_404(Category, slug=category_slug)
        products = Product.objects.filter(category=category, status='published')
        page = self.paginate_queryset(products)
        serializer = ProductListSerializer(page, many=True)
        return self.get_paginated_response(serializer.data)

class CategoryViewSet(viewsets.ReadOnlyModelViewSet):
    """
    ViewSet for viewing categories.
    """
    queryset = Category.objects.all()
    serializer_class = CategorySerializer
    lookup_field = 'slug'

    @action(detail=True, methods=['get'])
    def products(self, request, slug=None):
        """Get all products in this category"""
        category = self.get_object()
        products = Product.objects.filter(category=category, status='published')
        page = StandardResultsSetPagination()
        result_page = page.paginate_queryset(products)
        serializer = ProductListSerializer(result_page, many=True)
        return page.get_paginated_response(serializer.data)

class ReviewViewSet(viewsets.ModelViewSet):
    """
    ViewSet for managing reviews.
    """
    queryset = Review.objects.filter(is_approved=True)
    serializer_class = ReviewSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]

    def get_permissions(self):
        if self.action in ['create']:
            permission_classes = [permissions.IsAuthenticated]
        else:
            permission_classes = [permissions.IsAuthenticatedOrReadOnly]
        return [permission() for permission in permission_classes]

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)

class UserViewSet(viewsets.ReadOnlyModelViewSet):
    """
    ViewSet for viewing user information.
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = [permissions.IsAuthenticated]

    @action(detail=False, methods=['get'])
    def me(self, request):
        """Get current user information"""
        serializer = self.get_serializer(request.user)
        return Response(serializer.data)

    @action(detail=True, methods=['get'])
    def products(self, request, pk=None):
        """Get all products created by this user"""
        user = self.get_object()
        products = Product.objects.filter(created_by=user)
        page = StandardResultsSetPagination()
        result_page = page.paginate_queryset(products)
        serializer = ProductListSerializer(result_page, many=True)
        return page.get_paginated_response(serializer.data)

# API Views
@api_view(['GET'])
@permission_classes([permissions.AllowAny])
def api_stats(request):
    """Get API statistics"""
    stats = {
        'total_products': Product.objects.count(),
        'published_products': Product.objects.filter(status='published').count(),
        'total_categories': Category.objects.count(),
        'total_reviews': Review.objects.filter(is_approved=True).count(),
        'total_users': User.objects.count(),
    }

    # Add rating statistics
    avg_rating = Review.objects.filter(is_approved=True).aggregate(
        avg_rating=Avg('rating')
    )['avg_rating'] or 0

    stats['average_rating'] = round(avg_rating, 1)

    return Response(stats)

@api_view(['GET'])
@permission_classes([permissions.AllowAny])
def search_products(request):
    """Search products with advanced filtering"""
    query = request.GET.get('q', '')
    category = request.GET.get('category', '')
    min_price = request.GET.get('min_price', '')
    max_price = request.GET.get('max_price', '')
    rating = request.GET.get('rating', '')

    products = Product.objects.filter(status='published')

    if query:
        products = products.filter(
            models.Q(name__icontains=query) |
            models.Q(description__icontains=query)
        )

    if category:
        products = products.filter(category__slug=category)

    if min_price:
        products = products.filter(price__gte=min_price)

    if max_price:
        products = products.filter(price__lte=max_price)

    # Filter by rating (products with average rating >= specified rating)
    if rating:
        rating_int = int(rating)
        product_ids = []
        for product in products:
            avg_rating = product.reviews.filter(is_approved=True).aggregate(
                avg_rating=Avg('rating')
            )['avg_rating'] or 0
            if avg_rating >= rating_int:
                product_ids.append(product.id)
        products = Product.objects.filter(id__in=product_ids)

    page = StandardResultsSetPagination()
    result_page = page.paginate_queryset(products)
    serializer = ProductListSerializer(result_page, many=True)
    return page.get_paginated_response(serializer.data)

# 6. URLs (api/urls.py)
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from rest_framework.authtoken import views as drf_views
from . import api_views

router = DefaultRouter()
router.register(r'products', api_views.ProductViewSet, basename='product')
router.register(r'categories', api_views.CategoryViewSet, basename='category')
router.register(r'reviews', api_views.ReviewViewSet, basename='review')
router.register(r'users', api_views.UserViewSet, basename='user')

urlpatterns = [
    path('', include(router.urls)),
    path('auth/login/', drf_views.obtain_auth_token, name='api_token_auth'),
    path('stats/', api_views.api_stats, name='api_stats'),
    path('search/', api_views.search_products, name='search_products'),
]

# 7. Main URLs (project/urls.py additions)
from django.urls import path, include

urlpatterns = [
    # ... existing urls
    path('api/', include('api.urls')),
]

# 8. Admin (api/admin.py)
from django.contrib import admin
from django.utils.html import format_html
from .models import Product, Category, Review, Tag

@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
    list_display = ['name', 'slug', 'created_at']
    prepopulated_fields = {'slug': ('name',)}
    search_fields = ['name']

class ReviewInline(admin.TabularInline):
    model = Review
    extra = 1
    readonly_fields = ['user', 'created_at']

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    list_display = ['name', 'category', 'price', 'status', 'is_featured', 'created_by', 'thumbnail']
    list_filter = ['status', 'is_featured', 'category', 'created_at']
    search_fields = ['name', 'description']
    prepopulated_fields = {'slug': ('name',)}
    inlines = [ReviewInline]
    readonly_fields = ['created_at', 'updated_at']

    def thumbnail(self, obj):
        if obj.image:
            return format_html('<img src="{}" width="50" height="50" />', obj.image.url)
        return 'No image'
    thumbnail.short_description = 'Image'

    def save_model(self, request, obj, form, change):
        if not change:  # If creating a new object
            obj.created_by = request.user
        super().save_model(request, obj, form, change)

@admin.register(Review)
class ReviewAdmin(admin.ModelAdmin):
    list_display = ['product', 'user', 'rating', 'is_approved', 'created_at']
    list_filter = ['rating', 'is_approved', 'created_at']
    search_fields = ['product__name', 'user__username', 'title']
    actions = ['approve_reviews']

    def approve_reviews(self, request, queryset):
        queryset.update(is_approved=True)
    approve_reviews.short_description = 'Mark selected reviews as approved'

@admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
    list_display = ['name']
    search_fields = ['name']

# 9. Commands to Run
"""
# Install dependencies:
pip install -r requirements.txt

# Setup database:
python manage.py makemigrations api
python manage.py migrate

# Create superuser:
python manage.py createsuperuser

# Create sample data:
python manage.py shell

# In shell:
from api.models import Category, Product, Tag
from django.contrib.auth.models import User

user = User.objects.get(username='admin')

# Create categories
electronics = Category.objects.create(name='Electronics', description='Electronic devices and gadgets')
books = Category.objects.create(name='Books', description='Books and literature')

# Create products
laptop = Product.objects.create(
    name='Laptop Pro',
    description='High-performance laptop for professionals',
    price=1299.99,
    category=electronics,
    status='published',
    created_by=user
)

# Create tags
tech_tag = Tag.objects.create(name='technology')
laptop.tags.add(tech_tag)

# Run development server:
python manage.py runserver

# API Endpoints:
# GET /api/products/ - List all products
# GET /api/products/<slug>/ - Get product detail
# POST /api/products/ - Create product (requires auth)
# PUT /api/products/<slug>/ - Update product (requires auth)
# DELETE /api/products/<slug>/ - Delete product (requires auth)
# GET /api/categories/ - List all categories
# GET /api/categories/<slug>/ - Get category details
# GET /api/products/featured/ - Get featured products
# GET /api/products/by_category/?slug=<slug> - Get products by category
# GET /api/stats/ - Get API statistics
# GET /api/search/?q=<query> - Search products
# POST /api/auth/login/ - Get auth token
# GET /api/users/me/ - Get current user (requires auth)
"""

💻 Django Advanced Patterns python

🔴 complex ⭐⭐⭐⭐⭐

Advanced Django patterns including custom managers, signals, middleware, background tasks, and performance optimization

⏱️ 65 min 🏷️ django, advanced, optimization, patterns, middleware
Prerequisites: Advanced Django, Database optimization, Python advanced concepts
# Django Advanced Patterns

# 1. Custom Model Managers
# models/managers.py
from django.db import models
from django.db.models import Q, Count, Avg
from django.utils import timezone

class ProductManager(models.Manager):
    """Custom manager for Product model with common query methods"""

    def get_queryset(self):
        return super().get_queryset().select_related('category', 'created_by')

    def active(self):
        """Get only active/published products"""
        return self.get_queryset().filter(status='published')

    def featured(self):
        """Get only featured products"""
        return self.active().filter(is_featured=True)

    def by_category(self, category_slug):
        """Get products by category slug"""
        return self.active().filter(category__slug=category_slug)

    def search(self, query):
        """Search products by name and description"""
        return self.active().filter(
            Q(name__icontains=query) | Q(description__icontains=query)
        )

    def with_avg_rating(self):
        """Annotate products with average rating"""
        return self.get_queryset().annotate(
            avg_rating=Avg('reviews__rating', filter=Q(reviews__is_approved=True))
        )

# 2. Custom Middleware
# middleware.py
import time
from django.utils.deprecation import MiddlewareMixin
from django.http import JsonResponse
from django.core.cache import cache

class RequestTimingMiddleware(MiddlewareMixin):
    """Middleware to measure request processing time"""

    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
            response['X-Response-Time'] = f"{duration:.3f}s"
        return response

# 3. Custom Management Commands
# management/commands/generate_reports.py
from django.core.management.base import BaseCommand
from django.db.models import Count, Avg, Sum
from datetime import datetime, timedelta
import json

class Command(BaseCommand):
    help = 'Generate various business reports'

    def handle(self, *args, **options):
        reports = {
            'total_products': Product.objects.count(),
            'published_products': Product.objects.filter(status='published').count(),
            'generated_at': datetime.now().isoformat()
        }

        with open('reports.json', 'w') as f:
            json.dump(reports, f, indent=2)

# 4. Custom Template Tags and Filters
# templatetags/shop_tags.py
from django import template
from django.utils.safestring import mark_safe

register = template.Library()

@register.filter
def currency(value):
    """Format currency"""
    try:
        return f"${float(value):,.2f}"
    except (ValueError, TypeError):
        return "$0.00"

@register.filter
def percentage(value):
    """Convert decimal to percentage"""
    try:
        return f"{float(value) * 100:.1f}%"
    except (ValueError, TypeError):
        return "0%"

# 5. Custom Validators
# validators.py
from django.core.exceptions import ValidationError
import re

def validate_sku(value):
    """Validate SKU format"""
    pattern = r'^[A-Z0-9]{3,20}$'
    if not re.match(pattern, value):
        raise ValidationError('SKU must be 3-20 uppercase letters and numbers.')

# 6. Usage Examples
"""
# Test custom managers:
from myapp.models import Product

# Get featured products with average rating
featured_products = Product.objects.featured().with_avg_rating()

# Search products
search_results = Product.objects.search('laptop').active()

# Test custom filters in templates:
{{ product.price|currency }}
{{ product.discount_percentage|percentage }}
"""