(二十)管理后台与对象范围
1. 从模型生成维护界面
# 项目文件:reading_project/src/library/admin.py
from django.contrib import admin
from .models import Book, BookChange, Tag
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
# 列表与对象操作都检查范围,新建时由当前账号指定归属。
list_display = ["title", "owner", "finished", "tag_names"]
search_fields = ["title"]
list_filter = ["finished"]
exclude = ["owner"]
filter_horizontal = ["tags"]
def get_queryset(self, request):
books = (
super()
.get_queryset(request)
.select_related("owner")
.prefetch_related("tags")
)
return books if request.user.is_superuser else books.filter(owner=request.user)
@admin.display(description="标签")
def tag_names(self, book):
return ", ".join(tag.name for tag in book.tags.all())
def save_model(self, request, obj, form, change):
if not change:
obj.owner = request.user
super().save_model(request, obj, form, change)
BookChange.objects.create(book=obj, action="updated" if change else "created")admin.register 登记模型,list_display 选择列表列,search_fields 和 list_filter 提供检索与筛选,filter_horizontal 提供多对多选择。tag_names 使用预取标签组织显示,不在每一行重新查一次。
新增时的 owner 从当前后台用户赋值,不在编辑字段里。普通维护账号的 QuerySet 只保留自己的书;超级用户可以查看全站记录。修改记录跟随后台保存写入。
2. 列表范围之外继续检查单个对象
# 续写同一文件:reading_project/src/library/admin.py
def has_view_permission(self, request, obj=None):
# 保留 Django 的模型权限要求,再核对当前记录属于谁。
return super().has_view_permission(request, obj) and self.owns(request, obj)
def has_change_permission(self, request, obj=None):
return super().has_change_permission(request, obj) and self.owns(request, obj)
def has_delete_permission(self, request, obj=None):
return super().has_delete_permission(request, obj) and self.owns(request, obj)
@staticmethod
def owns(request, obj):
return (
obj is None or request.user.is_superuser or obj.owner_id == request.user.pk
)
admin.site.register(Tag) # 标签是共享分类,普通维护账号没有其修改权限。
admin.site.site_header = "阅读记录管理"后台还调用 has_view_permission、has_change_permission、has_delete_permission,先保留 Django 的模型权限检查,再核对对象归属。维护账号不能通过直接改地址编辑其他用户的书。共享标签名称由有相应权限的管理人员维护。