【问题标题】:Django admin: Making a required field read-onlyDjango admin:将必填字段设为只读
【发布时间】:2018-06-12 13:36:46
【问题描述】:

我有许多模型与 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相同的问题。

关于如何实现这一点的任何想法?谢谢!

【问题讨论】:

  • 你可以在 django admin 中使用 readonly_fields
  • 我的问题比这更复杂。

标签: django django-admin


【解决方案1】:

我通常做的是将模型中的字段设置为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',)

希望这行得通!

【讨论】:

【解决方案2】:

这是ModelAdmin.readonly_fields 文档。

【讨论】:

    【解决方案3】:

    我遇到了同样的问题。一种解决方法是在 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 设置字段的标签。如果您不设置,则该字段将标记为“人员方法”

    大概在 OPs 的情况下 get_readonly_fields 变成:

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

    【讨论】:

    • 仅使用此答案中的get_readonly_fields 可以解决非方法来源(正常)字段的问题。不确定整个答案将如何工作 - 方法源字段无论如何都是只读的。
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      您可以扩展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()

      【讨论】:

        【解决方案6】:

        field1 此处为必填字段,在管理屏幕中设为只读

        model.py

        class ModelName(models.Model):
          field1 = models.ForeignKey(
              ModelA, 
              on_delete=models.CASCADE,
              db_column='col1',
              related_name='col1',
              verbose_name='col1'
          )
          field2 = models.ForeignKey(
              ModelB, 
              on_delete=models.CASCADE,
              db_column='col2',
              related_name='col2',
              verbose_name='col2'
          )
        

        admin.py

            @admin.register(ModelName)
            class AdminClassName(admin.ModelAdmin):
                fields = ('field1', 'field2')
                readonly_fields = ('field1')
        

        【讨论】:

          猜你喜欢
          • 2019-04-14
          • 2013-01-11
          • 2018-09-13
          • 2010-11-27
          • 2012-11-28
          • 1970-01-01
          • 2019-03-14
          • 2018-06-03
          • 2023-04-05
          相关资源
          最近更新 更多