42

我正在尝试将所有字段设为只读而不明确列出它们。

就像是:

class CustomAdmin(admin.ModelAdmin):
    def get_readonly_fields(self, request, obj=None):
        if request.user.is_superuser:
            return self.readonly_fields

        return self.fields

问题CustomAdmin.fields不是在这一点上设置。

有任何想法吗?

4

11 回答 11

47

False从 django 2.1 开始,您可以通过从ModelAdmin'方法返回来防止编辑,同时允许查看,has_change_permission如下所示:

class CustomAdmin(admin.ModelAdmin):
    def has_change_permission(self, request, obj=None):
        return False

(这在 django 2.1 之前将不起作用,因为它还会拒绝任何仅尝试查看的用户的权限。)

于 2018-10-30T17:47:22.823 回答
42

小心,self.model._meta.fields 不一定是 CustomAdmin 拥有的相同字段!

“管理员的所有字段”看起来更像这样:

from django.contrib import admin
from django.contrib.admin.utils import flatten_fieldsets

class CustomAdmin(admin.ModelAdmin):
    def get_readonly_fields(self, request, obj=None):
        if request.user.is_superuser:
            return self.readonly_fields

        if self.declared_fieldsets:
            return flatten_fieldsets(self.declared_fieldsets)
        else:
            return list(set(
                [field.name for field in self.opts.local_fields] +
                [field.name for field in self.opts.local_many_to_many]
            ))
于 2012-12-11T23:17:36.037 回答
25

好的,现在有这个:

class CustomAdmin(admin.ModelAdmin):
    def get_readonly_fields(self, request, obj=None):
        # ...

        return [f.name for f in self.model._meta.fields]

仍在寻找不那么丑陋的方法。

于 2012-12-11T10:13:51.293 回答
12

您可以遍历模型元字段:

def get_readonly_fields(self, request, obj=None):
    if obj:
        self.readonly_fields = [field.name for field in obj.__class__._meta.fields]
    return self.readonly_fields
于 2012-12-11T10:10:44.210 回答
5

对于内联(选项卡或堆栈)

def get_readonly_fields(self, request, obj=None):
    fields = []
    for field in self.model._meta.get_all_field_names():
        if field != 'id':
            fields.append(field)
    return fields

def has_add_permission(self, request):
    return False
于 2015-02-03T08:33:06.333 回答
4

这对我来说适用于 Django 1.10

def get_readonly_fields(self, request, obj=None):
    if request.user.is_superuser:
        return self.readonly_fields

    return list(set(
        [field.name for field in self.opts.local_fields] +
        [field.name for field in self.opts.local_many_to_many]
    ))
于 2017-03-18T17:21:11.897 回答
3

如果有人仍在寻找更好的方法,您可以像这样使用它:

@admin.register(ClassName)
class ClassNameAdmin(admin.ModelAdmin):
    readonly_fields = [field.name for field in ClassName._meta.fields]

ClassName 是您的模型类。

于 2021-04-12T12:33:54.087 回答
0

我的要求是相似的。我只需要将一个字段显示为 read-only 。这很好用:

class ChoiceInline(admin.TabularInline):
    model = Choice
    extra = 1
    fields = ['choice_text', 'votes']
    readonly_fields = ['votes']

class QuestionAdmin(admin.ModelAdmin):
    #fields = ['pub_date', 'question_text']
    fieldsets = [
        (None, {'fields': ['question_text']}),
        ('Date Information', {'fields': ['pub_date']}),
    ]
    search_fields = ['question_text']


    inlines = [ChoiceInline]

参考:C:\Python27\Lib\site-packages\django\contrib\admin\options.py

于 2018-02-27T11:40:46.620 回答
0

假设您已将 user_mode 定义为;

Admin, Customers and Staff

如果您想拒绝员工(当然还有客户)删除客户、产品、订单等的特权...

你的代码去;

def get_readonly_fields(self, request: HttpRequest, obj=None):
    if request.user.user_mode != "Admin":
        return self.readonly_fields + ['user_mode']
    return super().get_readonly_fields(request, obj)

其中 user_mode = 保存用户类型的模型字段。

注意:我的代码使用“Pylance”(如 JS 中的打字稿)

于 2021-05-26T08:07:53.970 回答
-1

使用 get_fieldsets 您可以从表单中获取所有字段

def get_readonly_fields(self, request, obj=None):
    readonly = []
    for fs in self.get_fieldsets(request, obj):
        if len(fs) > 1:
            readonly += fs[1].get('fields', [])
    return readonly
于 2013-10-11T12:37:54.857 回答
-1
@admin.register(Hero)
class HeroAdmin(admin.ModelAdmin, ExportCsvMixin):
    ...
    readonly_fields = ["father", "mother", "spouse"]

参考: https ://books.agiliq.com/projects/django-admin-cookbook/en/latest/changeview_readonly.html

于 2020-03-14T08:33:23.860 回答