我有许多与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
字段的值。
我已经调查了一个解决方案,该解决方案涉及创建一个可以选择性地禁用此字段的自定义表单(类似this或this),但是(a)我没有成功获取它工作,(b)似乎是一个看起来更简单的情况的代码。我也研究过使用exclude
,但遇到了与read_only
相同的问题。
有关如何实现这一目标的任何想法?谢谢!
答案 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()