Доступ только к собственным записям из Django админки
Иногда нужно, чтобы каждый пользователь админки Django мог видеть и редактировать только свои записи. По умолчанию такая возможность не доступна, но с помощью нехитрых действий можно всё исправить.
Суть подхода заключается в добавлении к нашей модели внешнего ключа на модель пользователя Django, а затем переопределение некоторых методов класса, отвечающего за генерацию админки.
Администратор сайта видит все записи и может менять их владельцев (или создавать объекты от чужого имени). Остальные пользователи, имеющие доступ в панель администрирования, могут создавать и редактировать только свои записи.
Обратите внимание на атрибуты blank и null у поля user.
Так как поле будет заполняться автоматически, то нужно разрешить Django оставлять его пустым (blank=True).
null=True необходим для корректной работы нашего кода. Вообще, поле всегда будет содержать id пользователя и было бы правильно указать null=False, но из-за внутреннего устройства Django такой подход не пройдет.
Разберемся с кодом.
Метод save_model отвечает за автозаполнение поля user. Несколько несложных условий подставляют необходимый id пользователя.
Метод preprocess_list_display добавляет колонку user в список объектов, если его просматривает администратор и удаляет колонку для обычных пользователей. Обратите внимание, что сперва мы проверяем, есть ли запись в list_display и если её нет, то добавляем, а потом уже смотрим кто просматривает список.
При создании экземпляра EntryAdmin все его поля становятся глобальными для процесса, поэтому если мы удалим колонку list_display для обычного пользователя и не добавим для администратора, то администратор колонку не увидит. Именно поэтому мы каждый раз её вставляем в список.
Метод preprocess_search_fields делает тоже, что и preprocess_list_display, но только для search_fields. Фактически мы дали возможность администратору не только видеть автора записи, но и осуществлять поиск по его username.
Оба предыдущих метода вызываются из переопределенного changelist_view.
Метод queryset возвращает все записи для администратора и персональные записи для обычных пользователей. При изменении записи, обращение к ней идет через этот самый queryset, поэтому если пользователь пытается напрямую получить доступ к чужому объекту (введет в строку браузера что-то вроде /admin/app/entry/3/), то ему вернется HTTP 404.
Метод get_fieldsets подключает user_fieldsets в случае обычных пользователей или же генерирует fieldsets на основе данных модели Entry.
Вот и все, осталось только назначить пользователям необходимые права «can add entry», «can change entry» и т.д. А также поставить галочку напротив поля «Статус персонала» на странице редактирования данных пользователя. «Статус персонала» разрешит человеку входить в административную часть сайта.
Суть подхода заключается в добавлении к нашей модели внешнего ключа на модель пользователя Django, а затем переопределение некоторых методов класса, отвечающего за генерацию админки.
Администратор сайта видит все записи и может менять их владельцев (или создавать объекты от чужого имени). Остальные пользователи, имеющие доступ в панель администрирования, могут создавать и редактировать только свои записи.
models.py
<pre># -*- coding: utf-8 -*-
from django.db import models
from django.contrib.auth.models import User
class Entry(models.Model):
user = models.ForeignKey(User, verbose_name=u"пользователь", blank=True, null=True)
title = models.CharField(u"заголовок", max_length=100)
def __unicode__(self):
return self.title
class Meta:
verbose_name = u"""запись"""
verbose_name_plural = u"""записи"""</pre>
Обратите внимание на атрибуты blank и null у поля user.
Так как поле будет заполняться автоматически, то нужно разрешить Django оставлять его пустым (blank=True).
null=True необходим для корректной работы нашего кода. Вообще, поле всегда будет содержать id пользователя и было бы правильно указать null=False, но из-за внутреннего устройства Django такой подход не пройдет.
admin.py
<pre># -*- coding: utf-8 -*-
from django.contrib import admin
from app.models import Entry
class EntryAdmin(admin.ModelAdmin):
# Поля, доступные для редактирования простым пользователям.
# Разрешаем только title
user_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('title',)
}),
)
list_display = ['title', 'user']
raw_id_list_displayfields = ('user',)
search_fields = ['title', 'user__username']
def save_model(self, request, obj, form, change):
if form.is_valid():
if not request.user.is_superuser or not form.cleaned_data["user"]:
obj.user = request.user
obj.save()
elif form.cleaned_data["user"]:
obj.user = form.cleaned_data["user"]
obj.save()
def preprocess_list_display(self, request):
if 'user' not in self.list_display:
self.list_display.insert(self.list_display.__len__(), 'user')
if not request.user.is_superuser:
if 'user' in self.list_display:
self.list_display.remove('user')
def preprocess_search_fields(self, request):
if 'user__username' not in self.search_fields:
self.search_fields.insert(self.search_fields.__len__(), 'user__username')
if not request.user.is_superuser:
if 'user__username' in self.search_fields:
self.search_fields.remove('user__username')
def changelist_view(self, request, extra_context=None):
self.preprocess_list_display(request)
self.preprocess_search_fields(request)
return super(EntryAdmin, self).changelist_view(request)
def queryset(self, request):
if request.user.is_superuser:
return super(EntryAdmin, self).queryset(request)
else:
qs = super(EntryAdmin, self).queryset(request)
return qs.filter(user=request.user)
def get_fieldsets(self, request, obj=None):
if request.user.is_superuser:
return super(EntryAdmin, self).get_fieldsets(request, obj)
return self.user_fieldsets
admin.site.register(Entry, EntryAdmin)</pre>
Разберемся с кодом.
Метод save_model отвечает за автозаполнение поля user. Несколько несложных условий подставляют необходимый id пользователя.
Метод preprocess_list_display добавляет колонку user в список объектов, если его просматривает администратор и удаляет колонку для обычных пользователей. Обратите внимание, что сперва мы проверяем, есть ли запись в list_display и если её нет, то добавляем, а потом уже смотрим кто просматривает список.
При создании экземпляра EntryAdmin все его поля становятся глобальными для процесса, поэтому если мы удалим колонку list_display для обычного пользователя и не добавим для администратора, то администратор колонку не увидит. Именно поэтому мы каждый раз её вставляем в список.
Метод preprocess_search_fields делает тоже, что и preprocess_list_display, но только для search_fields. Фактически мы дали возможность администратору не только видеть автора записи, но и осуществлять поиск по его username.
Оба предыдущих метода вызываются из переопределенного changelist_view.
Метод queryset возвращает все записи для администратора и персональные записи для обычных пользователей. При изменении записи, обращение к ней идет через этот самый queryset, поэтому если пользователь пытается напрямую получить доступ к чужому объекту (введет в строку браузера что-то вроде /admin/app/entry/3/), то ему вернется HTTP 404.
Метод get_fieldsets подключает user_fieldsets в случае обычных пользователей или же генерирует fieldsets на основе данных модели Entry.
Вот и все, осталось только назначить пользователям необходимые права «can add entry», «can change entry» и т.д. А также поставить галочку напротив поля «Статус персонала» на странице редактирования данных пользователя. «Статус персонала» разрешит человеку входить в административную часть сайта.
0 комментариев