Просмотр разрешений в 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 -нас/админ/пользователь . Нужна помощь!**


person Tameen Malik    schedule 16.04.2014    source источник
comment
127.0.0.1:8000/en-us/admin/user, разве это не должно быть 127.0.0.1:8000/en-us/admin/auth/user?   -  person elssar    schedule 28.04.2014
comment
Как указано ниже: по умолчанию права просмотра и ModelAdmin.has_view_permission были представленный в Django 2.1.   -  person djvg    schedule 16.01.2019


Ответы (2)


Django 2.1 добавил разрешение на просмотр к разрешениям по умолчанию. Приведенное ниже решение может работать в более ранних версиях Django. https://docs.djangoproject.com/en/2.1/releases/2.1/#model-view-permission


Это рабочее решение, протестированное в Django 1.6.2.

[X] 1. Added 'view' to default permission list: OK
[X] 2. Test the 'view' permission is added to all models: OK

[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, чтобы включить «представление», в той же самой идее сделайте следующее:

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. Изменить разрешение «просмотр», чтобы сделать форму только для чтения: хорошо, но у меня есть другое решение, см. выше

person MoiTux    schedule 29.04.2014
comment
Спасибо :), но я не понимаю шаг 3 - И шаг 4 для файла contrib/admin/options.py @MoiTux - person Tameen Malik; 01.05.2014
comment
Это генерирует ОШИБКУ: AttributeError в /admin/auth/user/ Тип исключения: AttributeError Значение исключения: объект «UserAdmin» не имеет атрибута «has_view_permission» Местоположение исключения: \django\contrib\admin\options.py в changelist_view, строка 1295 - person Tameen Malik; 01.05.2014
comment
@TameenMalik идея для contrib/admin/options.py состоит в том, чтобы добавлять has_view_permission «каждый раз», когда есть has_change_permission. Я не получил никакой ошибки, но я просто тестирую с базовым администратором. - person MoiTux; 02.05.2014
comment
@TameenMalik Я могу без проблем зайти в админку пользователя - person MoiTux; 02.05.2014
comment
@TameenMalik Мне жаль, что я сделал ошибку при копировании/вставке кода. Теперь все должно быть в порядке. - person MoiTux; 02.05.2014
comment
какая ошибка, пожалуйста, обновите правильный код? - person Tameen Malik; 02.05.2014
comment
Я обновил свои ответы, прежде чем сказать, что сделал ошибку. Речь шла об изменении в add_view, которое должно быть в change_view. - person MoiTux; 02.05.2014
comment
спасибо, теперь все работает :) я наградил вас +50! еще одна вещь: можно перейти к просмотру пользователя (другой HTML-странице), щелкнув auth/users, а не переходя на страницу выбранной пользовательской формы! - person Tameen Malik; 05.05.2014
comment
Рад, что это работает, извините, но я не понимаю, о чем вы спрашиваете. Возможно, это нужно сделать в другом вопросе? - person MoiTux; 06.05.2014

Добавление разрешения «просмотр» в список разрешений по умолчанию

Ваше решение работает, но вам действительно следует избегать редактирования исходного кода, если это возможно. Есть несколько способов сделать это в рамках:

<сильный>1. Добавить разрешение во время post_syncdb():

В файле под your_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», все типы контента могут быть проверены, чтобы узнать, есть ли у них разрешение «просмотр», и если нет, создать его.

<сильный>2. Добавьте разрешение в параметр Мета-разрешения:

В каждой модели вы должны добавить что-то вроде этого к ее Meta параметрам:

class Pizza(models.Model):
    cheesiness = models.IntegerField()

    class Meta:
        permissions = (
            ('view_pizza', 'Can view pizza'),
        )

Это будет выполнено так же, как 1, за исключением того, что вам придется вручную добавлять его в каждый класс.

<сильный>3. НОВОЕ в Django 1.7: добавьте разрешение в мета default_permissions вариант:

В Django 1.7 они добавили мета-опцию default_permissions. В каждой модели вы должны добавить «просмотр» к опции default_permissions:

class Pizza(models.Model):
    cheesiness = models.IntegerField()

    class Meta:
        default_permissions = ('add', 'change', 'delete', 'view')
person pcoronel    schedule 01.05.2014
comment
Я разместил этот ответ на тот же (но более четкий) вопрос пользователя Add Permission to Django Admin - person pcoronel; 01.05.2014
comment
Если вы еще не используете 1.7, я бы посоветовал пока сделать либо №1, либо №2 — они выполняют то же самое, что и №3, но работают с более ранними версиями Django. Хотя, если обновление до 1.7 не будет слишком сложным для вашей системы/программы, сделайте это. В конечном счете, главное заключается в том, что вместо изменения исходного кода используйте один из вышеперечисленных методов, а затем просто используйте user.has_perm('my_app.view_mymodel'), чтобы проверить, есть ли у пользователя разрешение. - person pcoronel; 01.05.2014