Как я могу изменить Django, чтобы создать разрешение на «просмотр»? - PullRequest
31 голосов
/ 26 августа 2009

Я недавно начал использовать django для администрирования большого существующего приложения, которое органически росло за эти годы с помощью twisted.web. Я начал экспериментировать с django и его автоматическим интерфейсом администратора, и я был очень доволен результатами.

Одна вещь, которая, по-видимому, отсутствует для моих целей, - это возможность предоставить пользователям доступ только для чтения к данным. Например, у нас есть роль, где людям разрешено входить в систему и создавать заказы на покупку. Они также должны иметь возможность просматривать, но не редактировать данные других клиентов или продуктов.

Как мне создать разрешения на "просмотр" в администраторе django, чтобы пользователи могли изменять данные для одних таблиц, в то же время имея доступ только для чтения к другим?

Обновление: Django Admin, кажется, дает мне CUD интерфейса CRUD. Как получить часть «Только чтение» со связанными разрешениями и группами?

Обновление 2010-февраль-12: Django 1.2 теперь будет доступен только для чтения. Подробности ниже.


Я ответил на свой вопрос, наверное. Перемещение контента вниз к реальному ответу ниже.

Ответы [ 6 ]

35 голосов
/ 28 августа 2009

Так я изменил Django 1.0.2, чтобы добавить разрешения на «просмотр». Извините, различий нет.

[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. Проверка разрешения 'view' добавлена ​​для всех моделей

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 к элементам формы. Не все браузеры поддерживают это, но для моих целей я могу требовать, чтобы пользователи использовали правильный. Пример отключен / только для чтения

Обнаружено, что не все браузеры поддерживают "только чтение", поэтому некоторые элементы управления устанавливаются только для чтения, а другие - на отключенные. Это позволяет пользователям при необходимости копировать данные из текстовых элементов управления.

#/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 %}
11 голосов
/ 29 апреля 2012

Этот фрагмент сделает суперпользователя единственным с правами записи.

class AdminOwn(admin.ModelAdmin):
    def get_readonly_fields(self, request, obj=None):
        if request.user.is_superuser:
            return self.readonly_fields
        #get all fields as readonly
        fields = [f.name for f in self.model._meta.fields]
        return fields
6 голосов
/ 26 августа 2009

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

Обновление: Извините, я неправильно понял вопрос, потому что неправильно истолковал слово view, чтобы придать ему значение Django, а не «только для чтения». Если вы хотите использовать только для чтения с помощью администратора, я думаю, вам нужно будет немного поработать. См. эту ветку , где Джеймс Беннетт (менеджер релиза Django) говорит:

Как вы найдете, выполнив поиск архивы этого списка, это не что-то интерфейс администратора Django предназначен для поддержки, и поэтому любой решение должно прийти полностью от того, что вы пишете свой собственный код.

и

Администратор Django работает на трех разрешения: «добавить», «изменить» и "удалять". Там нет "вид, но сделать без изменений "разрешение, следовательно, нет возможности применить такой ограничение без выполнения значительных пользовательское кодирование.

Дополнительная работа будет включать добавление разрешения «только для чтения» для определенных моделей и изменение базовых шаблонов администратора, чтобы проверить, есть ли у пользователя это разрешение - и если да, то отключение определенных элементов управления (таких как кнопки сохранения) и создание других только для чтения. Это предотвратит случайные манипуляции, но вам также может понадобиться изменить логику на стороне сервера, чтобы проверить то же разрешение, чтобы избежать любых POST, сделанных хитрым способом, чтобы обойти разрешения.

3 голосов
/ 17 октября 2012

Вы можете создать разрешение «только для чтения» в своей модели и использовать код jasuca с модификацией:

models.py:

class MyModel(models.Model):
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=256, null=True, blank=True)

    class Meta:
        permissions = (
            ('readonly_mymodel','Readonly MyModel'),
        )

admin.py:

class MyModelAdmin(admin.ModelAdmin):
    def get_readonly_fields(self, request, obj=None):
        if not request.user.is_superuser and request.user.has_perm('mymodel.readonly_mymodel'):
            return [f.name for f in self.model._meta.fields]
        return self.readonly_fields

В админке приложения вы должны дать пользователю разрешение на «изменение» и «только чтение».

2 голосов
/ 27 января 2010

Возможность добавлять поля только для чтения в представление администратора теперь включена в Django версии 1.2.

См. Билет № 342 http://code.djangoproject.com/ticket/342

См. Номер ревизии 11965 http://code.djangoproject.com/changeset/11965

см. Документацию http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.readonly_fields

0 голосов
/ 18 января 2012

Вы можете создавать группы в модуле авторизации. Затем в admin.py, основанном на входе в группу пользователей, установите атрибут readonly_fields для modeladmin. Добавьте метод def has_add_permission (self, request) для возврата false для группы с разрешением только для чтения. Дайте добавить, изменить разрешения для группы. Они смогут читать только атрибуты модели.

...