Исключить поля в Django admin для пользователей, отличных от суперпользователя

У меня есть простой класс MyUser с PermissionsMixin. user.is_superuser равно True только для суперпользователей. Я хотел бы сделать что-то похожее на это в admin.py:

    if request.user.is_superuser:
        fieldsets = (
            (None, {'fields': ('email', 'password')}),
            ('Permissions', {'fields': ('is_admin','is_staff')}),
            ('Place', {'fields': ('place',)}),
            ('Important dates', {'fields': ('last_login',)}),
        )
    else:
        fieldsets = (
            (None, {'fields': ('email', 'password')}),
            #('Permissions', {'fields': ('is_admin','is_staff')}),
            ('Place', {'fields': ('place',)}),
            ('Important dates', {'fields': ('last_login',)}),
        )

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

Ответ 1

Если вы правильно поняли, что вы хотите сделать, это переопределить метод get_form для ModelAdmin. Основываясь на примере из документации django, он будет выглядеть примерно так:

class MyUserAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        self.exclude = []
        if not request.user.is_superuser:
            self.exclude.append('Permissions') #here!
        return super(MyUserAdmin, self).get_form(request, obj, **kwargs)

Теперь вам может понадобиться немного взломать и, возможно, переопределить метод сохранения. Я сделал что-то подобное не так давно, это не так сложно (и документы фантастичны).

Возможно, будет более простое решение, но ваш вопрос будет общим, и вы не разделили свою модель пользователя, поэтому я не могу точно сказать, как это можно сделать. Надеюсь, это поможет!

Ответ 2

Принятый ответ близок, но, как указывают другие, get_form вызывается несколько раз в том же экземпляре модели администратора, и экземпляр повторно используется, поэтому вы можете в итоге повторить поля или другие пользователи, увидев поля после self.fields изменен. Попробуйте это в Django <= 1.6:

class MyAdmin(admin.ModelAdmin):

    normaluser_fields = ['field1','field2']
    superuser_fields = ['special_field1','special_field2']

    def get_form(self, request, obj=None, **kwargs):
        if request.user.is_superuser:
            self.fields = self.normaluser_fields + self.superuser_fields
        else:
            self.fields = self.normaluser_fields

        return super(MyAdmin, self).get_form(request, obj, **kwargs)

Похоже, Django 1.7 вводит метод get_fields(), который вы можете переопределить, что намного лучше:

https://github.com/django/django/blob/d450af8a2687ca2e90a8790eb567f9a25ebce85b/django/contrib/admin/options.py#L276

Ответ 3

Согласно Django Docs, правильный способ - создать ModelForm для суперпользователей, а другой для обычных пользователей. Затем вы указываете каждую форму в методе get_form вашего ModelAdmin:

class MyModelAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        if request.user.is_superuser:
            kwargs['form'] = MySuperuserForm
        else:
            kwargs['form'] = MyNormalForm
        return super(MyModelAdmin, self).get_form(request, obj, **kwargs)

Ответ 4

Начиная Django 1.7, вы можете заменить базовый класс своего администратора модели чем-то вроде:

class SuperuserAwareModelAdmin(admin.ModelAdmin):
    superuser_fields = None
    superuser_fieldsets = None

    def get_fieldsets(self, request, obj = None):
        if request.user.is_superuser and self.superuser_fieldsets:
            return (self.fieldsets or tuple()) + self.superuser_fieldsets
        return super(SuperuserAwareModelAdmin, self).get_fieldsets(request, obj)

    def get_fields(self, request, obj = None):
        if request.user.is_superuser and self.superuser_fields:
            return (self.fields or tuple()) + self.superuser_fields
        return super(SuperuserAwareModelAdmin, self).get_fields(request, obj)

Пример:

class MyModelAdmin(SuperuserAwareModelAdmin):
    superuser_fieldsets = (
        (_('Permissions'), {'fields': ('is_staff', )}),
    )

Базовый класс SuperuserAwareModelAdmin также может быть создан как mixin.

Ответ 5

Django теперь имеет get_exclude метод на ModelAdmin для исключения полей программно.

Он принимает текущий запрос и объект (если есть) в качестве аргумента. Вы можете поставить проверку на аргумент запроса, чтобы увидеть, являются ли они суперпользователем, и проверить

class MyModelAdmin(admin.ModelAdmin):
    def get_exclude(self, request, obj=None):
        excluded = super().get_exclude(request, obj) or [] # get overall excluded fields

        if not request.user.is_superuser: # if user is not a superuser
            return excluded + ['extra_field_to_exclude']

        return excluded # otherwise return the default excluded fields if any