(十九)操作权限与对象归属分别判断
Book 的 Meta.permissions 增加 library.export_book。迁移后 Django 建立这条权限,用户或组取得它后,has_perm 可以检查。书架页面按 perms.library.export_book 显示导出按钮,入口也执行同一权限要求:
# 续写同一文件:reading_project/src/library/views.py
@login_required
@permission_required("library.export_book", raise_exception=True)
def export_books(request):
# 全局操作权限通过后,仍然只查询当前用户的记录。
response = HttpResponse(content_type="text/csv; charset=utf-8")
response["Content-Disposition"] = 'attachment; filename="books.csv"'
response.write("\ufeff")
writer = csv.writer(response)
writer.writerow(["title", "finished", "tags"])
for book in Book.objects.filter(owner=request.user).prefetch_related("tags"):
writer.writerow(
[
book.title,
int(book.finished),
json.dumps([tag.name for tag in book.tags.all()], ensure_ascii=False),
]
)
return responsepermission_required(..., raise_exception=True) 对已登录但没有该操作权限的用户返回 403。通过后仍只查 owner=request.user,所以“可以导出”并没有变成“可以导出其他人的书”。
CSV 响应设置内容类型与下载文件名,csv.writer 把普通列表逐行写进响应,开头的 BOM 帮助常用表格程序识别 UTF-8。导出可以接回第十一章的数据分析。
# 项目文件:demos/permission_steps.py
# 比较普通账户、持有权限的账户和管理员,让同一操作展示不同权限结果。
from lab import lab
with lab():
from django.contrib.auth import get_user_model
from django.test import Client
User = get_user_model()
for name in ["alice", "bob", "manager"]:
user = User.objects.get(username=name)
client = Client()
client.force_login(user)
print(
name,
"后台标记",
user.is_staff,
"导出权限",
user.has_perm("library.export_book"),
"导出响应",
client.get("/export.csv").status_code,
)
manager = User.objects.get(username="manager")
print("manager 模型修改权限", manager.has_perm("library.change_book"))
print("manager 书架条数", manager.books.count())alice 获得导出权限,bob 没有,manager 获得后台书籍模型维护权限但没有导出权限。is_staff 负责后台入口,模型操作权限、用户组和记录归属继续分别判断。