每天40分玩转Django:Django管理界面

时间:2024-12-22 09:28:36

Django管理界面

一、今日学习内容概述

学习模块 重要程度 预计学时 主要内容
基础管理配置 ⭐⭐⭐⭐⭐ 1小时 ModelAdmin基本配置
自定义管理界面 ⭐⭐⭐⭐⭐ 2小时 界面定制、动作添加
内联模型管理 ⭐⭐⭐⭐ 1.5小时 内联显示、关联编辑
高级定制功能 ⭐⭐⭐⭐ 1.5小时 权限控制、界面美化

二、基础模型定义

# models.py
from django.db import models
from django.contrib.auth.models import User

class Category(models.Model):
    name = models.CharField('分类名称', max_length=100)
    description = models.TextField('描述', blank=True)
    created_at = models.DateTimeField('创建时间', auto_now_add=True)

    class Meta:
        verbose_name = '分类'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

class Product(models.Model):
    STATUS_CHOICES = [
        ('draft', '草稿'),
        ('published', '已发布'),
        ('archived', '已归档'),
    ]
    
    name = models.CharField('商品名称', max_length=200)
    category = models.ForeignKey(
        Category, 
        on_delete=models.CASCADE,
        related_name='products',
        verbose_name='分类'
    )
    price = models.DecimalField('价格', max_digits=10, decimal_places=2)
    stock = models.PositiveIntegerField('库存')
    description = models.TextField('描述')
    status = models.CharField(
        '状态',
        max_length=10,
        choices=STATUS_CHOICES,
        default='draft'
    )
    created_by = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        verbose_name='创建者'
    )
    created_at = models.DateTimeField('创建时间', auto_now_add=True)
    updated_at = models.DateTimeField('更新时间', auto_now=True)

    class Meta:
        verbose_name = '商品'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name

class ProductImage(models.Model):
    product = models.ForeignKey(
        Product,
        on_delete=models.CASCADE,
        related_name='images',
        verbose_name='商品'
    )
    image = models.ImageField('图片', upload_to='products/')
    is_primary = models.BooleanField('是否主图', default=False)
    created_at = models.DateTimeField('创建时间', auto_now_add=True)

    class Meta:
        verbose_name = '商品图片'
        verbose_name_plural = verbose_name

三、自定义管理界面

3.1 基础管理类

# admin.py
from django.contrib import admin
from django.utils.html import format_html
from .models import Category, Product, ProductImage

@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
    list_display = ('name', 'description', 'products_count', 'created_at')
    search_fields = ('name',)
    list_per_page = 20
    
    def products_count(self, obj):
        return obj.products.count()
    products_count.short_description = '商品数量'

class ProductImageInline(admin.TabularInline):
    model = ProductImage
    extra = 1
    fields = ('image', 'is_primary')

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    # 列表页配置
    list_display = ('name', 'category', 'price', 'stock', 'status', 
                   'created_by', 'created_at', 'get_image')
    list_filter = ('status', 'category', 'created_at')
    search_fields = ('name', 'description')
    list_editable = ('price', 'stock', 'status')
    list_per_page = 20
    
    # 详情页配置
    fieldsets = (
        ('基本信息', {
            'fields': ('name', 'category', 'price', 'stock')
        }),
        ('详细描述', {
            'fields': ('description',),
            'classes': ('collapse',)
        }),
        ('状态信息', {
            'fields': ('status', 'created_by')
        })
    )
    
    # 内联显示图片
    inlines = [ProductImageInline]
    
    def get_image(self, obj):
        primary_image = obj.images.filter(is_primary=True).first()
        if primary_image:
            return format_html(
                '<img src="{}" width="50" height="50" />',
                primary_image.image.url
            )
        return '无图片'
    get_image.short_description = '主图'
    
    def save_model(self, request, obj, form, change):
        if not change:  # 新建商品时
            obj.created_by = request.user
        super().save_model(request, obj, form, change)
        
    def get_queryset(self, request):
        qs = super().get_queryset(request)
        if request.user.is_superuser:
            return qs
        return qs.filter(created_by=request.user)

3.2 自定义动作

# admin.py
from django.contrib import admin, messages
from django.http import HttpResponse
import csv

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    actions = ['export_as_csv', 'publish_products', 'archive_products']
    
    def export_as_csv(self, request, queryset):
        meta = self.model._meta
        field_names = [field.name for field in meta.fields]
        
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = 'attachment; filename={}.csv'.format(meta)
        
        writer = csv.writer(response)
        writer.writerow(field_names)
        for obj in queryset:
            writer.writerow([getattr(obj, field) for field in field_names])
            
        return response
    export_as_csv.short_description = '导出所选商品为CSV'
    
    def publish_products(self, request, queryset):
        updated = queryset.update(status='published')
        self.message_user(
            request,
            f'成功发布 {updated} 个商品',
            messages.SUCCESS
        )
    publish_products.short_description = '发布所选商品'
    
    def archive_products(self, request, queryset):
        updated = queryset.update(status='archived')
        self.message_user(
            request,
            f'成功归档 {updated} 个商品',
            messages.SUCCESS
        )
    archive_products.short_description = '归档所选商品'

四、自定义表单

# forms.py
from django import forms
from .models import Product

class ProductAdminForm(forms.ModelForm):
    class Meta:
        model = Product
        fields = '__all__'
        
    def clean_price(self):
        price = self.cleaned_data.get('price')
        if price and price < 0:
            raise forms.ValidationError('价格不能为负数')
        return price

# admin.py中使用自定义表单
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    form = ProductAdminForm

五、管理界面流程图

在这里插入图片描述

六、高级定制功能

6.1 自定义后台主题

# admin.py
admin.site.site_header = '商品管理系统'
admin.site.site_title = '商品管理'
admin.site.index_title = '欢迎使用商品管理系统'

# templates/admin/base_site.html
{% extends "admin/base.html" %}
{% load static %}

{% block extrastyle %}
<style>
    #header {
        background: #2c3e50;
        color: #fff;
    }
    .module h2, .module caption {
        background: #34495e;
    }
    div.breadcrumbs {
        background: #34495e;
    }
    a:link, a:visited {
        color: #2c3e50;
    }
</style>
{% endblock %}

6.2 自定义列表显示

# admin.py
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    def get_list_display(self, request):
        """动态设置列表显示字段"""
        if request.user.is_superuser:
            return ('name', 'category', 'price', 'stock', 'status', 
                    'created_by', 'created_at', 'get_image')
        return ('name', 'category', 'price', 'stock', 'status')
    
    def get_readonly_fields(self, request, obj=None):
        """动态设置只读字段"""
        if request.user.is_superuser:
            return ()
        if obj:  # 编辑时
            return ('created_by', 'created_at')
        return ('created_at',)

6.3 自定义过滤器

# admin.py
from django.contrib.admin import SimpleListFilter

class StockStatusFilter(SimpleListFilter):
    title = '库存状态'
    parameter_name = 'stock_status'
    
    def lookups(self, request, model_admin):
        return (
            ('out', '无库存'),
            ('low', '库存不足'),
            ('enough', '库存充足'),
        )
    
    def queryset(self, request, queryset):
        if self.value() == 'out':
            return queryset.filter(stock=0)
        if self.value() == 'low':
            return queryset.filter(stock__gt=0, stock__lt=10)
        if self.value() == 'enough':
            return queryset.filter(stock__gte=10)

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    list_filter = (StockStatusFilter, 'status', 'category')

七、内联模型示例

# admin.py
from django.contrib import admin
from .models import Order, OrderItem

class OrderItemInline(admin.TabularInline):
    model = OrderItem
    extra = 1
    fields = ('product', 'quantity', 'price')
    raw_id_fields = ('product',)
    
    def get_readonly_fields(self, request, obj=None):
        if obj:  # 如果是编辑已存在的订单
            return ('price',)
        return ()

@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
    list_display = ('order_number', 'customer', 'total_amount', 
                   'status', 'created_at')
    list_filter = ('status', 'created_at')
    search_fields = ('order_number', 'customer__username')
    inlines = [OrderItemInline]
    readonly_fields = ('order_number', 'total_amount')

八、权限控制

# admin.py
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    def has_add_permission(self, request):
        """控制添加权限"""
        return request.user.has_perm('products.add_product')
    
    def has_change_permission(self, request, obj=None):
        """控制修改权限"""
        if not obj:
            return True
        # 只允许超级管理员和创建者修改
        return request.user.is_superuser or obj.created_by == request.user
    
    def has_delete_permission(self, request, obj=None):
        """控制删除权限"""
        if not obj:
            return True
        # 只允许超级管理员删除
        return request.user.is_superuser

九、总结

  1. 今日要点回顾:

    • Django管理界面的基本配置
    • 自定义管理界面的外观和功能
    • 内联模型的使用方法
    • 权限控制的实现
  2. 应用场景:

    • 内容管理系统
    • 电商后台管理
    • 数据维护界面
    • 运营管理系统
  3. 注意事项:

    • 合理设置权限
    • 优化查询性能
    • 注意数据安全
    • 保持界面友好
  4. 扩展建议:

    • 集成富文本编辑器
    • 添加数据导入导出
    • 自定义管理命令
    • 添加数据统计功能

怎么样今天的内容还满意吗?再次感谢朋友们的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务*,还请给个赞,谢谢!