只读Django admin inline中的现有项目的Readonly

use*_*888 21 django django-admin

我在Django管理员中有一个表格内联模型.我需要1个字段在创建后不可更改,但将其设置为readonly(通过readonly_fields),工作正常,但在单击"添加其他项目"而不是下拉列表时将字段转换为标签.

有没有办法保持字段只读,但仍允许使用正确的字段输入创建新项目?

谢谢!

托马斯

编辑:管理通过自定义小部件来计算出来

class ReadOnlySelectWidget(forms.Select):
    def render(self, name, value, attrs=None):
        if value:
            final_attrs = self.build_attrs(attrs, name=name)
            output = u'<input value="%s" type="hidden" %s />' % (value, flatatt(final_attrs))
            return mark_safe(output + str(self.choices.queryset.get(id=value)))
        else:
            return super(ReadOnlySelectWidget, self).render(name, value, attrs)
Run Code Online (Sandbox Code Playgroud)

如果有值,它只会将其变为隐藏,在每种情况下都不会起作用(仅适用于1个只读字段).

ole*_*sse 40

遇到同样的问题,我遇到了这个问题:

创建两个内联对象,一个没有更改权限,另一个包含所有字段只读.包括在模型管理员中.

class SubscriptionInline(admin.TabularInline):
    model = Subscription
    extra = 0
    readonly_fields = ['subscription', 'usedPtsStr', 'isActive', 'activationDate', 'purchaseDate']

    def has_add_permission(self, request):
        return False

class AddSupscriptionInline(admin.TabularInline):
    model = Subscription
    extra = 0
    fields = ['subscription', 'usedPoints', 'isActive', 'activationDate', 'purchaseDate']

    def has_change_permission(self, request, obj=None):
        return False

    # For Django Version > 2.1 there is a "view permission" that needs to be disabled too (https://docs.djangoproject.com/en/2.2/releases/2.1/#what-s-new-in-django-2-1)
    def has_view_permission(self, request, obj=None):
        return False
Run Code Online (Sandbox Code Playgroud)

将它们包含在同一模型管理员中:

class UserAdmin(admin.ModelAdmin):
    inlines = [ AddSupscriptionInline, SubscriptionInline]
Run Code Online (Sandbox Code Playgroud)

要添加新订阅,我AddSubscriptionInline在管理员中使用.保存后,新订阅将从内联中消失,但现在确实SubscriptionInline以只读方式显示在内联中.

因为SubscriptionInline,重要的是要提及extra = 0,因此它不会显示垃圾只读订阅.最好隐藏添加选项SubscriptionInline,以允许仅添加通过AddSubscriptionInline设置has_add_permission始终返回False.

根本不完美,但它对我来说是最好的选择,因为我必须提供在用户管理页面上添加订阅的功能,但是在添加一个之后,它应该仅通过内部应用程序逻辑进行更改.

  • 我做了类似于此但修改了新记录的内联的查询集(示例中的AddSubscriptionInline):`def queryset(self,request):return super(AddSubscriptionInline,self).queryset(request).none()`并添加`max_num = 0`到现有记录的内联(示例中为SubscriptionInline). (2认同)

Tra*_*oyd 7

你可以只用一个内联来实现这一点,如下所示:

class MyInline(admin.TabularInline):
    fields = [...]
    extra = 0

    def has_change_permission(self, request, obj):
        return False
Run Code Online (Sandbox Code Playgroud)

  • 很棒的答案,这就是我一直在寻找的。从 Django 3.x 开始,args 应该是“(self, request, obj)”(假设有相关模型)并且只需要“has_change_permission”。 (2认同)
  • 这个答案很好,但前提是您希望*所有*字段对于现有项目都是只读的。从技术上讲,最初的问题是关于特定领域的,因此在答案中澄清这一限制可能会更好? (2认同)

Ily*_*nov 1

这可以通过猴子补丁来实现。

以下示例将使现有 AdminNote 对象的“note”字段变为只读。与其他答案中建议的将字段转换为隐藏不同,这实际上将从提交/验证工作流程中删除字段(这更安全并使用现有的字段渲染器)。

#
# app/models.py
#

class Order(models.Model):
    pass

class AdminNote(models.Model):
    order = models.ForeignKey(Order)
    time = models.DateTimeField(auto_now_add=True)
    note = models.TextField()


#
# app/admin.py
#

import monkey_patches.admin_fieldset

...

class AdminNoteForm(forms.ModelForm):
    class Meta:
        model = AdminNote

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.get_readonly_fields():
            del self.fields[field]

    def get_readonly_fields(self):
        if self.instance.pk:
            return ['note']
        return []


class AdminNoteInline(admin.TabularInline):
    model = AdminNote
    form = AdminNoteForm
    extra = 1
    fields = 'note', 'time'
    readonly_fields = 'time',


@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
    inlines = AdminNoteInline,


#
# monkey_patches/admin_fieldset.py
#

import django.contrib.admin.helpers


class Fieldline(django.contrib.admin.helpers.Fieldline):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if hasattr(self.form, 'get_readonly_fields'):
            self.readonly_fields = list(self.readonly_fields) + list(self.form.get_readonly_fields())

django.contrib.admin.helpers.Fieldline = Fieldline
Run Code Online (Sandbox Code Playgroud)