Django admin:将必填字段设为只读

时间:2018-01-02 21:09:58

标签: django django-admin

我有许多与Person模型有ForeignKey关系的模型。例如:

class PersonData(BaseModel):
    person = models.ForeignKey(Person)
    data = models.TextField()

我想锁定管理员,以便在创建PersonData对象后,管理员用户可以更改数据,但无法更改Person

起初看起来很简单 - 我把它放在PersonDataAdmin课程中:

def get_readonly_fields(self, request, obj=None):
    if obj:
        return self.readonly_fields + ('person',)
    return self.readonly_fields

在显示方面,它按预期工作 - 我看到person的值,但它显示为灰色,因此我无法更改它 - 但是当我尝试更改数据并提交时表单,我收到一条错误消息,“请更正下面的错误。”没有其他消息出现,但通过一些挖掘,我发现表单缺少所需person字段的值。

我已经调查了一个解决方案,该解决方案涉及创建一个可以选择性地禁用此字段的自定义表单(类似thisthis),但是(a)我没有成功获取它工作,(b)似乎是一个看起来更简单的情况的代码。我也研究过使用exclude,但遇到了与read_only相同的问题。

有关如何实现这一目标的任何想法?谢谢!

5 个答案:

答案 0 :(得分:5)

我通常做的是将模型中的字段设置为editable = false,然后在admin.py中将字段设置为只读,如下所示

class PersonData(BaseModel):
    person = models.ForeignKey(Person, editable=false)
    data = models.TextField()

然后在admin.py

class PersonDataAdmin(admin.ModelAdmin):
    readonly_fields=('person',)

希望这有效!

答案 1 :(得分:0)

答案 2 :(得分:0)

我遇到了同样的问题。一种解决方法是在Admin类中定义一个方法,该方法返回要显示的只读字段的值。然后使用以前使用该字段名称的方法名称。 例如而不是:

class PersonDataAdmin(admin.ModelAdmin):
    readonly_fields=('person',)

使用:

class PersonDataAdmin(admin.ModelAdmin):
    readonly_fields=('person_method',)

    def person_method(self, obj):
        return obj.person

    person_method.short_description = 'Person'

short_description设置字段的标签。如果未设置,则该字段将被标记为“人事方法”

大概在OP中,get_readonly_fields变为:

def get_readonly_fields(self, request, obj=None):
    if obj:
        return self.readonly_fields + ('person_method',)
    return self.readonly_fields

答案 3 :(得分:0)

我遇到了与您完全相同的问题。检查您是否在管理类上使用了get_form。不知何故,这就是我遇到问题的原因。

答案 4 :(得分:0)

您可以扩展 ModelAdmin.get_form() 并使用 Field.disabled 禁用 person 字段,如下所示:

def get_form(self, request, obj=None, change=False, **kwargs):
    form = super().get_form(request, obj, change, **kwargs)
    if obj:
        form.base_fields['person'].disabled = True
    return form

这将防止 person 字段被修改。

但是,它的样式仍然是选择框,并且它旁边可能仍然有“更改”和“添加另一个”按钮。

这些按钮由 RelatedFieldWidgetWrapper 添加。删除它们的一种方法是删除包装器:

...
field = form.base_fields['person']
field.disabled = True
if isinstance(field.widget, RelatedFieldWidgetWrapper):
    # unwrap the widget
    field.widget = field.widget.widget

另一种方法是设置以下小部件属性:

...
if isinstance(field.widget, RelatedFieldWidgetWrapper):
    field.widget.can_add_related = False
    field.widget.can_change_related = False

如果您希望将该字段的样式设置为 readonly 字段,则需要做一些额外的工作。另请参阅 fieldset.html 模板和 AdminReadonlyField 以了解 django admin 如何显示外键 readonly_fields

另一种方法是实现自己的 ReadOnlyWidget,类似于 this,只需设置 form.base_fields['person'].widget = ReadOnlyWidget()