Просмотр разрешений в Django
Поскольку администратор django имеет три разрешения в своей авторизации: добавлять, изменять, удалять! Я хочу добавить разрешение на просмотр в этой авторизации в админ-панели. Я знаю, что мне нужно настроить разрешения, чтобы добавить разрешение на просмотр в "авторизации | разрешение | можно просматривать разрешение" для просмотра всех записей!
ПУТЬ:
[X] 1. Добавлен "просмотр" в список разрешений по умолчанию
#./contrib/auth/management/init.py
def _get_all_permissions(opts):
"Returns (codename, name) for all permissions in the given opts."
perms = []
for action in ('add', 'change', 'delete', 'view'):
perms.append((_get_permission_codename(action, opts), u'Can %s %s' % (action, opts.verbose_name_raw)))
return perms + list(opts.permissions)
[X] 2. Проверка разрешения "вид" добавлено для всех моделей
run manage.py syncdb
Я подтвердил, что разрешение на просмотр теперь добавлено для всех таблиц в таблице auth_permissions
[X] 3. Добавьте "get_view_permission" в класс модели по умолчанию.
Добавлено get_view_permission в модельный класс. Вы можете найти это в файле./db/models/options.py Это используется классом администратора на следующем шаге.
def get_view_permission(self):
return 'view_%s' % self.object_name.lower()
[X] 4. Добавьте "has_view_permission" в класс администратора по умолчанию
Просто чтобы быть последовательным, я собираюсь добавить "has_view_permission" в систему. Похоже, это должно быть где-то в contrib / admin / options.py. Убедитесь, что если у пользователя есть разрешение на изменение, то автоматически отображаются права на просмотр.
# /contrib/admin/options.py
# Added has_view_permissions
def has_view_permission(self, request, obj=None):
"""
Returns True if the given request has permission to change or view
the given Django model instance.
If obj is None, this should return True if the given request has
permission to change *any* object of the given type.
"""
opts = self.opts
return self.has_change_permission(request, obj) or \
request.user.has_perm(opts.app_label + '.' + opts.get_view_permission())
# modified get_model_perms to include 'view' too.
# No idea where this may be used, but trying to stay consistent
def get_model_perms(self, request):
"""
Returns a dict of all perms for this model. This dict has the keys
add, change, and delete and view mapping to the True/False
for each of those actions.
"""
return {
'add': self.has_add_permission(request),
'change': self.has_change_permission(request),
'delete': self.has_delete_permission(request),
'view': self.has_view_permission(request),
}
# modified response_add function to return the user to the mode list
# if they added a unit and have view rights
...
else:
self.message_user(request, msg)
# Figure out where to redirect. If the user has change permission,
# redirect to the change-list page for this object. Otherwise,
# redirect to the admin index.
#if self.has_change_permission(request, None):
if self.has_change_permission(request, None) or self.has_view_permission(request, None):
post_url = '../'
else:
post_url = '../../../'
return HttpResponseRedirect(post_url)
# modified the change_view function so it becomes the details
# for users with view permission
#if not self.has_change_permission(request, obj):
if not (self.has_change_permission(request, obj) or (self.has_view_permission(request, obj) and not request.POST)):
raise PermissionDenied
# modified the changelist_view function so it shows the list of items
# if you have view permissions
def changelist_view(self, request, extra_context=None):
"The 'change list' admin view for this model."
from django.contrib.admin.views.main import ChangeList, ERROR_FLAG
opts = self.model._meta
app_label = opts.app_label
#if not self.has_change_permission(request, None):
if not (self.has_change_permission(request, None) or self.has_view_permission(request, None)):
raise PermissionDenied
[X] 5. Обновите шаблон по умолчанию для отображения списка моделей, если у пользователя есть разрешение на просмотр.
Я изменил шаблон по умолчанию в contrib/admin/templates/admin/index.html. Это также может быть обработано путем копирования файла в локальный каталог шаблонов. Я внес изменения в оба, поэтому у меня есть копия, если позднее обновление перезаписывает мои изменения.
{% for model in app.models %}
<tr>
{% if model.perms.change %}
<th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
{% else %}
{% if model.perms.view %}
<th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
{% else %}
<th scope="row">{{ model.name }}</th>
{% endif %}
{% endif %}
[X] 6. Подтвердите, что пользователь может "просматривать", но не "менять" модель
Найденный contrib / admin / templatetags / admin_modify.py, по-видимому, управляет отображением кнопок сохранения / сохранения и продолжения или нет. Изменено поле "Сохранить" по умолчанию всегда True, чтобы проверить контекст и разрешения. Пользователь должен иметь возможность сохранить, если у него есть изменения или добавить разрешения.
'show_save': (change and context['has_change_permission']) or (context['add'] and context['has_add_permission'])
[X] 7. Удалить кнопку "Сохранить и добавить еще", если пользователь просматривает элемент
Снова изменил contrib / admin / templatetags / admin_modify.py. Я не знаю, что означает "save_as", так что, возможно, я что-то сломал, но, похоже, это работает.
#'show_save_and_add_another': context['has_add_permission'] and
# not is_popup and (not save_as or context['add']) ,
'show_save_and_add_another': not is_popup and
(( change and context['has_change_permission']) or (context['add'] and context['has_add_permission']))
and
(not save_as or context['add']),
[X] 8. Измените разрешение просмотра, чтобы сделать форму доступной только для чтения.
Если у пользователя есть разрешение на "просмотр" и "изменение", то ничего не делайте. Изменить вид переопределений.
Если пользователь имеет разрешение "просматривать" без "изменения", измените формы по умолчанию и добавьте атрибуты DISABLED или READONLY к элементам формы. Не все браузеры поддерживают это, но для моих целей я могу требовать, чтобы пользователи использовали правильный. [Отключено / Только для чтения пример][1]
Обнаружено, что не все браузеры поддерживают режим "только для чтения", поэтому некоторые элементы управления устанавливаются только для чтения, другие отключаются. Это позволяет пользователям при необходимости копировать данные из текстовых элементов управления.
#/django/contrib/admin/templates/admin/change_form.html
{# JavaScript for prepopulated fields #}
{% prepopulated_fields_js %}
</div>
</form></div>
{% if has_view_permission and not has_change_permission %}
<script type="text/javascript">
jQuery('input:text').attr('readonly', 'readonly');
jQuery('textarea').attr('readonly', 'readonly');
jQuery('input:checkbox').attr('disabled', true);
jQuery('select').attr('disabled', true);
jQuery('.add-another').hide();
</script>
{% endif %}
ИСТОЧНИК ОТВЕТА: Как я могу изменить django, чтобы создать разрешение на "просмотр"?
Вопрос: После приведенного выше ответа я сделал и могу видеть эту страницу 127.0.0.1:8000/en-us/admin/ только для чтения **, но пользователи в пользователях не видны 127.0.0.1:8000/en-us/ админ / пользователь. Нужна помощь!**
2 ответа
Django 2.1 добавил разрешение на просмотр к разрешениям по умолчанию. Приведенное ниже решение может работать в более ранних версиях Django. https://docs.djangoproject.com/en/2.1/releases/2.1/
Это рабочее решение, протестированное в Django 1.6.2.
[X] 1. Added 'view' to default permission list
: ХОРОШО[X] 2. Test the 'view' permission is added to all models
: ХОРОШО
[X] 3. Add "get_view_permission" to default model class.
больше бесполезно:
def get_add_permission(self):
"""
This method has been deprecated in favor of
`django.contrib.auth.get_permission_codename`. refs #20642
"""
warnings.warn(
"`Options.get_add_permission` has been deprecated in favor "
"of `django.contrib.auth.get_permission_codename`.",
PendingDeprecationWarning, stacklevel=2)
return 'add_%s' % self.model_name
И это относится ко всем этим методам get_foo_permission
[X] 4. Add "has_view_permission" to default admin class
должно быть:
def has_view_permission(self, request, obj=None):
"""
Returns True if the given request has permission to change or view
the given Django model instance.
If obj is None, this should return True if the given request has
permission to change *any* object of the given type.
"""
opts = self.opts
codename = get_permission_codename('view', opts)
return self.has_change_permission(request, obj) or \
request.user.has_perm("%s.%s" % (opts.app_label, codename))
если модель встроенная, проверьте ее правильность, поэтому необходимо знать о правильном представлении
def get_inline_instances(self, request, obj=None):
...
if not (inline.has_add_permission(request) or
inline.has_change_permission(request, obj) or
inline.has_delete_permission(request, obj) or
inline.has_view_permission(request, obj)): # add the view right
continue
...
Сделать модификацию на get_model_perms
чтобы включить 'view', в той же идее сделайте следующее:
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
...
context.update({
...
'has_view_permission': self.has_view_permission(request, obj), # add the view right
...
})
....
Разрешить "правильное представление" для отображения страницы (одного объекта) и отключить "правильное представление", чтобы сохранить изменения, сделанные на странице, избегать [X] 8. Modify "view" permission to make form read only
@csrf_protect_m
@transaction.atomic
def change_view(self, request, object_id, form_url='', extra_context=None):
"The 'change' admin view for this model."
model = self.model
opts = model._meta
obj = self.get_object(request, unquote(object_id))
# addthe view right
if not (self.has_view_permission(request, obj) or
self.has_change_permission(request, obj)):
raise PermissionDenied
...
inline_instances = self.get_inline_instances(request, obj)
# do not save the change if I'm not allowed to:
if request.method == 'POST' and self.has_change_permission(request, obj):
form = ModelForm(request.POST, request.FILES, instance=obj)
...
Разрешить "правильное представление" для отображения страницы (список всех объектов)
@csrf_protect_m
def changelist_view(self, request, extra_context=None):
"""
The 'change list' admin view for this model.
"""
from django.contrib.admin.views.main import ERROR_FLAG
opts = self.model._meta
app_label = opts.app_label
# allow user with the view right to see the page
if not (self.has_view_permission(request, None) or
self.has_change_permission(request, None)):
raise PermissionDenied
....
[X] 5. Update default template to list models if user has view permission
: ОК, но чтобы избежать изменения HTML-шаблона, отредактируйте этот файл: contrib / admin / site.py
class AdminSite(object):
@never_cache
def index(self, request, extra_context=None):
...
# add the view right
if perms.get('view', False) or perms.get('change', False):
try:
model_dict['admin_url'] = reverse('admin:%s_%s_changelist' % info, current_app=self.name)
except NoReverseMatch:
pass
...
def app_index(self, request, app_label, extra_context=None):
...
# add the view right
if perms.get('view', False) or perms.get('change', False):
try:
model_dict['admin_url'] = reverse('admin:%s_%s_changelist' % info, current_app=self.name)
except NoReverseMatch:
pass
...
[X] 6. Confirm user can "view" but not "change" the model
а также [X] 7. Remove "Save and Add another" button if user is viewing an item
: должно быть в порядке, но я сделал это:
'show_save_as_new': context['has_add_permission'] and not is_popup and change and save_as,
'show_save': context['has_change_permission'],
[X] 8. Измените разрешение на "просмотр", чтобы сделать форму доступной только для чтения: хорошо, но у меня есть другое решение, см. Выше
Добавление разрешения "просмотр" в список разрешений по умолчанию
Ваше решение работает, но вам следует избегать редактирования исходного кода, если это возможно. Есть несколько способов сделать это в рамках:
1. Добавьте разрешение во время post_syncdb()
:
В файле под вашим_app/management/
from django.db.models.signals import post_syncdb
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import Permission
def add_view_permissions(sender, **kwargs):
"""
This syncdb hooks takes care of adding a view permission too all our
content types.
"""
# for each of our content types
for content_type in ContentType.objects.all():
# build our permission slug
codename = "view_%s" % content_type.model
# if it doesn't exist..
if not Permission.objects.filter(content_type=content_type, codename=codename):
# add it
Permission.objects.create(content_type=content_type,
codename=codename,
name="Can view %s" % content_type.name)
print "Added view permission for %s" % content_type.name
# check for all our view permissions after a syncdb
post_syncdb.connect(add_view_permissions)
Всякий раз, когда вы запускаете команду syncdb, можно проверить все типы контента, чтобы увидеть, есть ли у них разрешение на просмотр, и если нет, создать.
- ИСТОЧНИК: Блог Nyaruka
2. Добавьте разрешение в опцию Meta permissions:
Под каждую модель вы бы добавили что-то подобное Meta
опции:
class Pizza(models.Model):
cheesiness = models.IntegerField()
class Meta:
permissions = (
('view_pizza', 'Can view pizza'),
)
Это будет сделано так же, как 1, за исключением того, что вы должны будете вручную добавить его в каждый класс.
3. НОВОЕ в Django 1.7, добавьте разрешение для опции Meta default_permissions:
В Django 1.7 добавлена мета-опция default_permissions. Под каждой моделью вы добавляете 'view' к опции default_permissions:
class Pizza(models.Model):
cheesiness = models.IntegerField()
class Meta:
default_permissions = ('add', 'change', 'delete', 'view')