Преглед на разрешенията в Django

Тъй като администраторът на django има три разрешения в своя auth: добавяне, промяна, изтриване! Искам да добавя разрешение за преглед в това удостоверяване в администраторския панел. Знам, че трябва да персонализирам разрешенията, за да добавя разрешение за преглед в „auth|permission|can view permission“, за да виждам всички записи!

НАЧИНЪТ:

[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="/bg{{ model.admin_url }}">{{ model.name }}</a></th>

    {% else %}

        {% if model.perms.view %}

            <th scope="row"><a href="/bg{{ 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/admin/user. Нужда от помощ!**


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, за да включите '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. Променете разрешението „изглед“, за да направите формуляра само за четене: Добре, но имам друго решение, вижте по-горе

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! още нещо възможно ли е да се преместите към userview (друга 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', всички типове съдържание могат да бъдат проверени, за да се види дали имат разрешение за 'view', и ако не, да се създаде такова.

2. Добавете разрешението към опцията за мета разрешения:

Под всеки модел бихте добавили нещо подобно към неговите 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 Meta. Под всеки модел бихте добавили „изглед“ към опцията default_permissions:

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

    class Meta:
        default_permissions = ('add', 'change', 'delete', 'view')
person pcoronel    schedule 01.05.2014
comment
Публикувах този отговор на същия (но по-ясен) въпрос на потребителя Добавяне на разрешение към 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