#Django Admin后台管理详解
#课程目标
- 理解Django Admin的功能和作用
- 掌握Admin界面的自定义配置
- 学会创建和管理管理员用户
- 了解Admin高级功能和安全设置
#Django Admin概述
Django Admin是Django框架内置的强大后台管理界面,它允许开发者快速创建一个功能完善的管理后台,用于管理应用程序的数据。Admin基于应用程序的模型自动生成管理界面,大大减少了开发时间。
#Admin的主要功能:
- 自动生成CRUD操作界面
- 用户认证和权限管理
- 数据导入导出
- 搜索和过滤功能
- 自定义界面和行为
#Admin基本配置
#创建超级用户
python manage.py createsuperuser按照提示输入用户名、邮箱和密码即可创建超级用户。
#注册模型到Admin
# admin.py
from django.contrib import admin
from .models import Article, Category, Tag
# 最简单的注册方式
admin.site.register(Article)
# 自定义Admin类
@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ['name', 'slug', 'created_at']
prepopulated_fields = {'slug': ('name',)}
search_fields = ['name']
list_filter = ['created_at']
# 也可以这样注册
class TagAdmin(admin.ModelAdmin):
list_display = ['name', 'usage_count']
search_fields = ['name']
admin.site.register(Tag, TagAdmin)#Admin界面自定义
#列表页面自定义
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
# 显示的字段
list_display = [
'title',
'author',
'category',
'status',
'created_at',
'view_count'
]
# 每页显示数量
list_per_page = 20
# 可点击排序的字段
list_display_links = ['title']
# 右侧过滤器
list_filter = [
'status',
'category',
'created_at',
'author'
]
# 搜索字段
search_fields = [
'title',
'content',
'author__username'
]
# 日期层次导航
date_hierarchy = 'created_at'
# 字段排序
ordering = ['-created_at']#表单页面自定义
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
# 字段分组
fieldsets = (
('基本信息', {
'fields': ('title', 'author', 'category')
}),
('内容', {
'fields': ('content', 'summary'),
'classes': ('wide',)
}),
('发布设置', {
'fields': ('status', 'tags', 'publish_date'),
'classes': ('collapse',) # 可折叠
}),
('统计信息', {
'fields': ('view_count', 'like_count'),
'classes': ('collapse',)
})
)
# 显示的字段
fields = ['title', 'content', 'author', 'category', 'status']
# 多对多字段的显示方式
filter_horizontal = ['tags'] # 水平显示多对多字段
# 或者
# filter_vertical = ['tags'] # 垂直显示多对多字段#表单布局自定义
class ArticleAdmin(admin.ModelAdmin):
# 使用TabularInline或StackedInline
class CategoryInline(admin.TabularInline): # 水平显示
model = ArticleCategory
extra = 1
class CommentInline(admin.StackedInline): # 垂直显示
model = Comment
extra = 0
readonly_fields = ['content', 'created_at']
inlines = [CategoryInline, CommentInline]
# 只读字段
readonly_fields = ['created_at', 'updated_at', 'view_count']
# 自定义动作
actions = ['make_published', 'make_draft', 'export_as_pdf']
def make_published(self, request, queryset):
"""批量发布文章"""
updated = queryset.update(status='published')
self.message_user(
request,
f'成功将 {updated} 篇文章设置为发布状态'
)
make_published.short_description = "批量发布选中的文章"
def make_draft(self, request, queryset):
"""批量设为草稿"""
updated = queryset.update(status='draft')
self.message_user(
request,
f'成功将 {updated} 篇文章设置为草稿状态'
)
make_draft.short_description = "批量设为草稿"#高级Admin功能
#自定义Admin类
from django.contrib import admin
from django.utils.html import format_html
from django.urls import reverse
from django.utils.safestring import mark_safe
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
list_display = [
'title',
'author',
'status',
'created_at',
'view_count',
'custom_actions'
]
list_filter = ['status', 'category', 'created_at']
search_fields = ['title', 'content', 'author__username']
date_hierarchy = 'created_at'
# 自定义列表操作列
def custom_actions(self, obj):
"""自定义操作按钮"""
edit_url = reverse('admin:myapp_article_change', args=[obj.pk])
view_url = reverse('article_detail', args=[obj.pk])
return format_html(
'<a class="button" href="{}" target="_blank">编辑</a> '
'<a class="button" href="{}" target="_blank">查看</a>',
edit_url,
view_url
)
custom_actions.short_description = '操作'
# 自定义查询集
def get_queryset(self, request):
qs = super().get_queryset(request)
if request.user.is_superuser:
return qs
return qs.filter(author=request.user)
# 自定义保存行为
def save_model(self, request, obj, form, change):
if not change: # 如果是新建
obj.author = request.user
super().save_model(request, obj, form, change)
# 自定义删除行为
def delete_model(self, request, obj):
# 可以在这里添加自定义删除逻辑
super().delete_model(request, obj)#Admin权限控制
class ArticleAdmin(admin.ModelAdmin):
def has_add_permission(self, request):
"""控制添加权限"""
# 只有超级用户和编辑可以添加
return request.user.is_superuser or request.user.groups.filter(name='Editor').exists()
def has_change_permission(self, request, obj=None):
"""控制修改权限"""
# 超级用户可以修改所有,普通用户只能修改自己的
if request.user.is_superuser:
return True
if obj is None:
return True
return obj.author == request.user
def has_delete_permission(self, request, obj=None):
"""控制删除权限"""
if request.user.is_superuser:
return True
if obj is None:
return False
return obj.author == request.user and obj.status == 'draft'
def get_readonly_fields(self, request, obj=None):
"""动态设置只读字段"""
readonly_fields = []
if not request.user.is_superuser:
readonly_fields.extend(['author', 'created_at'])
if obj and obj.status == 'published':
readonly_fields.append('author') # 已发布的文章不能更改作者
return readonly_fields#Admin样式和主题
#自定义Admin外观
# admin.py
from django.contrib import admin
from django.utils.html import format_html
# 自定义站点头部
admin.site.site_header = '我的网站管理后台'
admin.site.site_title = '管理后台'
admin.site.index_title = '欢迎来到我的网站管理后台'
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
list_display = [
'title',
'formatted_status',
'author',
'created_at'
]
def formatted_status(self, obj):
"""美化状态显示"""
status_colors = {
'draft': 'orange',
'published': 'green',
'archived': 'gray'
}
color = status_colors.get(obj.status, 'black')
return format_html(
'<span style="color: {}; font-weight: bold;">{}</span>',
color,
obj.get_status_display()
)
formatted_status.short_description = '状态'
formatted_status.admin_order_field = 'status'#自定义CSS样式
# admin.py
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
class Media:
css = {
'all': ('/static/admin/css/custom_admin.css',)
}
js = (
'/static/admin/js/custom_admin.js',
)
list_display = ['title', 'author', 'status', 'created_at']/* static/admin/css/custom_admin.css */
.module h2 {
background-color: #417690;
color: white;
padding: 10px;
}
.field-status {
font-weight: bold;
}
.draft {
color: orange;
}
.published {
color: green;
}
.archived {
color: gray;
}#Admin高级技巧
#批量操作
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
actions = [
'publish_selected',
'unpublish_selected',
'export_selected'
]
def publish_selected(self, request, queryset):
"""发布选中的文章"""
updated = queryset.update(status='published')
self.message_user(
request,
f'成功发布了 {updated} 篇文章。',
messages.SUCCESS
)
publish_selected.short_description = "发布选中的文章"
def unpublish_selected(self, request, queryset):
"""取消发布选中的文章"""
updated = queryset.update(status='draft')
self.message_user(
request,
f'成功取消发布 {updated} 篇文章。',
messages.INFO
)
unpublish_selected.short_description = "取消发布选中的文章"
def export_selected(self, request, queryset):
"""导出选中的文章"""
import csv
from django.http import HttpResponse
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="articles.csv"'
writer = csv.writer(response)
writer.writerow(['标题', '作者', '内容', '状态', '创建时间'])
for article in queryset:
writer.writerow([
article.title,
article.author.username,
article.content[:100], # 只导出前100个字符
article.status,
article.created_at
])
return response
export_selected.short_description = "导出选中的文章为CSV"#自定义Admin视图
from django.contrib import admin
from django.urls import path
from django.shortcuts import render
from django.http import JsonResponse
from .models import Article
class ArticleAdmin(admin.ModelAdmin):
list_display = ['title', 'author', 'status', 'created_at']
def get_urls(self):
urls = super().get_urls()
custom_urls = [
path('stats/', self.admin_site.admin_view(self.stats_view), name='article-stats'),
]
return custom_urls + urls
def stats_view(self, request):
"""自定义统计视图"""
articles_count = Article.objects.count()
published_count = Article.objects.filter(status='published').count()
draft_count = Article.objects.filter(status='draft').count()
context = {
'articles_count': articles_count,
'published_count': published_count,
'draft_count': draft_count,
'title': '文章统计',
}
return render(request, 'admin/stats.html', context)
admin.site.register(Article, ArticleAdmin)#Admin安全设置
#安全配置
# settings.py
# Admin安全设置
ADMIN_ENABLED = True # 控制是否启用Admin
# 只允许特定IP访问Admin
ALLOWED_ADMIN_IPS = [
'127.0.0.1',
'192.168.1.1',
]
# 自定义Admin URL
ADMIN_URL = 'secure_admin_panel/' # 不要使用默认的admin/
# 中间件中检查IP
"""
class AdminIPRestrictionMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.path.startswith('/admin/'):
ip = request.META.get('REMOTE_ADDR')
if ip not in ALLOWED_ADMIN_IPS:
return HttpResponseForbidden('Access denied')
response = self.get_response(request)
return response
"""#自定义Admin站点
# admin.py
from django.contrib.admin import AdminSite
from django.contrib.auth.models import User, Group
class MyAdminSite(AdminSite):
site_header = '我的网站管理后台'
site_title = '我的网站'
index_title = '欢迎使用我的网站管理后台'
def has_permission(self, request):
"""自定义权限检查"""
return request.user.is_superuser
# 创建自定义Admin站点实例
my_admin_site = MyAdminSite(name='myadmin')
# 注册模型到自定义站点
my_admin_site.register(Article, ArticleAdmin)
my_admin_site.register(Category, CategoryAdmin)
# 在urls.py中使用
"""
from django.urls import path, include
from myapp.admin import my_admin_site
urlpatterns = [
path('myadmin/', my_admin_site.urls),
# 其他URL...
]
"""#课程总结
本节课我们深入学习了Django Admin后台管理系统的各个方面,包括基本配置、界面自定义、高级功能、权限控制和安全设置等。Django Admin是开发过程中非常有用的工具,可以大大提高数据管理的效率。通过合理的配置和自定义,我们可以创建出功能强大且用户友好的管理后台。

