每天40分玩转Django:Django管理界面
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
九、总结
-
今日要点回顾:
- Django管理界面的基本配置
- 自定义管理界面的外观和功能
- 内联模型的使用方法
- 权限控制的实现
-
应用场景:
- 内容管理系统
- 电商后台管理
- 数据维护界面
- 运营管理系统
-
注意事项:
- 合理设置权限
- 优化查询性能
- 注意数据安全
- 保持界面友好
-
扩展建议:
- 集成富文本编辑器
- 添加数据导入导出
- 自定义管理命令
- 添加数据统计功能
怎么样今天的内容还满意吗?再次感谢朋友们的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!