Django应用 django-application

开发生产级别的 Django 应用,包括模型、视图、ORM 查询、认证和管理员界面,遵循 Django 的约定和最佳实践。

后端开发 0 次安装 0 次浏览 更新于 3/3/2026

Django 应用

概览

构建全面的 Django 网络应用,包括适当的模型设计、视图层次结构、数据库操作、用户认证和管理员功能,遵循 Django 约定和最佳实践。

何时使用

  • 创建 Django 网络应用
  • 设计模型和数据库模式
  • 实现视图和 URL 路由
  • 构建认证系统
  • 使用 Django ORM 进行数据库操作
  • 创建管理员界面和仪表板

指南

1. Django 项目设置

django-admin startproject myproject
cd myproject
python manage.py startapp users
python manage.py startapp products

2. ORM 模型设计

# users/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.contrib.auth import get_user_model

class CustomUser(AbstractUser):
    ROLE_CHOICES = [
        ('admin', '管理员'),
        ('user', '普通用户'),
    ]
    profile_picture = models.ImageField(upload_to='profiles/', null=True)
    role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='user')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['email']),
            models.Index(fields=['role']),
        ]

    def __str__(self):
        return self.email

# products/models.py
User = get_user_model()

class Product(models.Model):
    STATUS_CHOICES = [
        ('draft', '草稿'),
        ('published', '已发布'),
    ]

    title = models.CharField(max_length=200, db_index=True)
    slug = models.SlugField(unique=True)
    description = models.TextField()
    price = models.DecimalField(max_digits=10, decimal_places=2)
    stock = models.PositiveIntegerField(default=0)
    status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
    owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='products')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['-created_at']
        unique_together = ['slug', 'owner']

    def __str__(self):
        return self.title

class ProductReview(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='reviews')
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    rating = models.IntegerField(choices=[(i, i) for i in range(1, 6)])
    comment = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

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

3. 视图与类和函数方法

# products/views.py
from django.views import View
from django.views.generic import ListView, DetailView, CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render, redirect, get_object_or_404
from django.http import JsonResponse
from django.db.models import Q, Count, Avg
from rest_framework import viewsets, status
from rest_framework.response import Response
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated

from .models import Product, ProductReview
from .serializers import ProductSerializer

# 带有认证的类视图
class ProductListView(LoginRequiredMixin, ListView):
    model = Product
    template_name = 'products/list.html'
    context_object_name = 'products'
    paginate_by = 20

    def get_queryset(self):
        queryset = Product.objects.filter(status='published')

        # 搜索和过滤
        search = self.request.GET.get('q')
        if search:
            queryset = queryset.filter(
                Q(title__icontains=search) | Q(description__icontains=search)
            )

        # 价格范围过滤
        min_price = self.request.GET.get('min_price')
        max_price = self.request.GET.get('max_price')
        if min_price:
            queryset = queryset.filter(price__gte=min_price)
        if max_price:
            queryset = queryset.filter(price__lte=max_price)

        return queryset.annotate(
            review_count=Count('reviews'),
            avg_rating=Avg('reviews__rating')
        ).order_by('-created_at')

# REST API ViewSet
class ProductViewSet(viewsets.ModelViewSet):
    permission_classes = [IsAuthenticated]
    serializer_class = ProductSerializer
    queryset = Product.objects.all()

    def get_queryset(self):
        return Product.objects.filter(owner=self.request.user)

    @action(detail=True, methods=['post'])
    def add_review(self, request, pk=None):
        product = self.get_object()
        serializer = ProductReviewSerializer(data=request.data)

        if serializer.is_valid():
            serializer.save(product=product, author=request.user)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @action(detail=True, methods=['get'])
    def reviews(self, request, pk=None):
        product = self.get_object()
        reviews = product.reviews.all()
        serializer = ProductReviewSerializer(reviews, many=True)
        return Response(serializer.data)

4. 认证和权限

# users/views.py
from django.contrib.auth import authenticate, login, logout
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_protect
from rest_framework.authtoken.models import Token
from rest_framework.permissions import BasePermission

class IsOwner(BasePermission):
    def has_object_permission(self, request, view, obj):
        return obj.owner == request.user

@require_http_methods(['POST'])
@csrf_protect
def login_view(request):
    email = request.POST.get('email')
    password = request.POST.get('password')
    user = authenticate(request, username=email, password=password)

    if user is not None:
        login(request, user)
        token, created = Token.objects.get_or_create(user=user)
        return JsonResponse({
            'success': True,
            'token': token.key,
            'user_id': user.id
        })

    return JsonResponse({'error': 'Invalid credentials'}, status=401)

@require_http_methods(['POST'])
def logout_view(request):
    logout(request)
    return JsonResponse({'success': True})

5. 数据库查询和优化

# products/queries.py
from django.db.models import Q, Count, Avg, F, Case, When, Value
from django.db.models.functions import Coalesce
from .models import Product, ProductReview

# 使用 select_related 和 prefetch_related 优化查询
def get_product_details(product_id):
    return Product.objects.select_related('owner').prefetch_related(
        'reviews__author'
    ).get(id=product_id)

# 聚合查询
def get_top_products():
    return Product.objects.annotate(
        review_count=Count('reviews'),
        avg_rating=Avg('reviews__rating'),
        total_reviews=Count('reviews', distinct=True)
    ).filter(review_count__gt=0).order_by('-avg_rating')[:10]

# 复杂过滤
def search_products(query, category=None, min_price=None, max_price=None):
    queryset = Product.objects.filter(
        Q(title__icontains=query) | Q(description__icontains=query)
    )

    if category:
        queryset = queryset.filter(category=category)
    if min_price:
        queryset = queryset.filter(price__gte=min_price)
    if max_price:
        queryset = queryset.filter(price__lte=max_price)

    return queryset.select_related('owner')

# 批量操作
def bulk_update_stock(updates):
    products_to_update = []
    for product_id, new_stock in updates.items():
        product = Product.objects.get(id=product_id)
        product.stock = new_stock
        products_to_update.append(product)

    Product.objects.bulk_update(products_to_update, ['stock'])

6. URL 路由

# myproject/urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from rest_framework.authtoken.views import obtain_auth_token
from products.views import ProductViewSet

router = DefaultRouter()
router.register(r'products', ProductViewSet)

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include(router.urls)),
    path('api-token-auth/', obtain_auth_token),
]

7. 管理员界面定制

# products/admin.py
from django.contrib import admin
from .models import Product, ProductReview

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    list_display = ['title', 'price', 'stock', 'status', 'owner', 'created_at']
    list_filter = ['status', 'created_at', 'owner']
    search_fields = ['title', 'description']
    readonly_fields = ['created_at', 'updated_at']
    fieldsets = (
        ('基本信息', {
            'fields': ('title', 'slug', 'owner')
        }),
        ('详细信息', {
            'fields': ('description', 'price', 'stock', 'status')
        }),
        ('元数据', {
            'fields': ('created_at', 'updated_at'),
            'classes': ('collapse',)
        }),
    )

    def save_model(self, request, obj, form, change):
        if not change:
            obj.owner = request.user
        super().save_model(request, obj, form, change)

@admin.register(ProductReview)
class ProductReviewAdmin(admin.ModelAdmin):
    list_display = ['product', 'author', 'rating', 'created_at']
    list_filter = ['rating', 'created_at']
    readonly_fields = ['created_at']

最佳实践

✅ 应该做

  • 使用模型进行数据库操作
  • 在频繁查询的字段上实现适当的索引
  • 使用 select_related 和 prefetch_related 进行查询优化
  • 实施认证和权限
  • 使用 Django 表单进行表单验证
  • 缓存昂贵的查询
  • 使用管理命令进行批量操作
  • 实施日志记录以进行调试
  • 使用中间件处理跨领域问题
  • 验证用户输入

❌ 不应该做

  • 没有 ORM 使用原生 SQL
  • 没有优化的 N+1 查询问题
  • 将机密信息存储在代码中
  • 直接信任用户输入
  • 除非必要,否则不要重写模型中的 init
  • 在视图中进行同步重操作
  • 在生产中暴露堆栈跟踪
  • 除非必要,否则不要使用继承模型

完整示例

# settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'rest_framework',
    'users',
    'products'
]

AUTH_USER_MODEL = 'users.CustomUser'

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ]
}

# models.py + views.py (见上文部分)
# urls.py + admin.py (见上文部分)