🎯 Exemples recommandés
Balanced sample collections from various categories for you to explore
Exemples Django
Exemples du framework web Django incluant modèles, vues, templates, Django REST Framework et patterns Django modernes
💻 Django Hello World python
🟢 simple
⭐
Configuration de projet Django et application Hello World, incluant modèles, vues et 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>© 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
⭐⭐⭐⭐
Exemples avancés de Django REST API incluant sérialiseurs, viewsets, authentification et patterns de conception API
⏱️ 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)
"""
💻 Patterns Avancés Django python
🔴 complex
⭐⭐⭐⭐⭐
Patterns avancés Django incluant managers personnalisés, signaux, middleware, tâches de fond et optimisation des performances
⏱️ 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 }}
"""