Exemples Django
Exemples du framework web Django incluant modèles, vues, templates, Django REST Framework et patterns Django modernes
Key Facts
- Category
- Web Frameworks
- Items
- 3
- Format Families
- sample
Sample Overview
Exemples du framework web Django incluant modèles, vues, templates, Django REST Framework et patterns Django modernes This sample set belongs to Web Frameworks and can be used to test related workflows inside Elysia Tools.
💻 Django Hello World python
Configuration de projet Django et application Hello World, incluant modèles, vues et templates
# 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>© 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
Exemples avancés de Django REST API incluant sérialiseurs, viewsets, authentification et patterns de conception API
# 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)
"""
💻 Patterns Avancés Django python
Patterns avancés Django incluant managers personnalisés, signaux, middleware, tâches de fond et optimisation des performances
# 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 }}
"""