Django built-in chỉ có model-level permission — tức là quyền làm hành động X trên toàn bộ model Y, chứ không có object-level out-of-the-box.
Mỗi model tự sinh 4 permission khi migrate: add_post, change_post, delete_post, view_post. Muốn thêm custom thì khai báo trong Meta.permissions = [('publish_post', 'Can publish post')]. Group là một tập permission — gán user vào group thay vì gán từng perm cho từng user. Check quyền bằng user.has_perm('blog.publish_post') hoặc decorator @permission_required('blog.publish_post').
# Cho group editor có quyền publish
editors, _ = Group.objects.get_or_create(name='editors')
editors.permissions.add(Permission.objects.get(codename='publish_post'))
user.groups.add(editors)Object-level (user A chỉ sửa được post của chính mình) phải tự kiểm tra trong view/queryset hoặc cài django-guardian (thêm bảng phân quyền per-object).
Lỗi bảo mật phổ biến: chỉ check perm ở template ({% if perms.blog.publish_post %}) — đó là gating UI cho đẹp thôi, không phải security thật. Template check không chặn được POST trực tiếp tới endpoint. Mọi check perm bắt buộc phải làm ở view/serializer trước khi gọi save().
Django's built-in is model-level permission only (action X on all of model Y) — no object-level out of the box.
- Permission: each model auto-generates 4 perms at
migrate:add_post,change_post,delete_post,view_post. Add custom ones viaMeta.permissions = [('publish_post', 'Can publish post')]. - Group: a bundle of permissions. Assign users to groups instead of single perms.
- Check:
user.has_perm('blog.publish_post')or@permission_required('blog.publish_post').
# give editors group publish rights
editors, _ = Group.objects.get_or_create(name='editors')
editors.permissions.add(Permission.objects.get(codename='publish_post'))
user.groups.add(editors)Object-level (user A can only edit their own posts) must be enforced in the view/queryset, or use django-guardian (adds a per-object permission table).
Pitfall: Do not gate solely in templates ({% if perms.blog.publish_post %}) — that is UI hiding, not security. Always check in the view/serializer before save(). A template check does not stop a direct POST to the endpoint.