Python 现代开发学习笔记

(二十)管理后台与对象范围

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 的模型权限检查,再核对对象归属。维护账号不能通过直接改地址编辑其他用户的书。共享标签名称由有相应权限的管理人员维护。

后台先看 staff 与模型权限,再按账号缩小列表范围,直接对象操作还要核对归属,新增 owner 从当前用户设置而不读取伪造字段

笔记正文与全部题解 · Ctrl / ⌘ K