【问题标题】:how to show a django ModelForm field as uneditable如何将 django ModelForm 字段显示为不可编辑
【发布时间】:2011-08-17 05:28:29
【问题描述】:

通过django ModelForm 开始我的课程,我想让用户能够编辑博客中的条目。BlogEntry 有一个date,postedTime, title and content。我想向用户展示一个显示所有这些的编辑表单字段,但只有title and content as editabledate and postedTime should be shown as uneditable

class BlogEntry(models.Model):
   title = models.CharField(unique=True,max_length=50)
   description = models.TextField(blank=True)
   date = models.DateField(default=datetime.date.today)
   postedTime = models.TimeField(null=True)

...

对于添加条目,我以正常方式使用 ModelForm..

class BlogEntryAddForm(ModelForm):
    class Meta:
        model = BlogEntry
...

但是我如何创建编辑表单?我希望它到show the date,postedTime as uneditable(但仍将它们显示在表单上)并让用户编辑title and description

如果我使用exclude in class Meta 作为日期和发布时间,这将导致它们不会出现在表单上。那么,我怎样才能将它们显示为不可编辑?

class BlogEntryEditForm(ModelForm):
    class Meta:
        model = BlogEntry
        ...?...

【问题讨论】:

    标签: python django forms model edit


    【解决方案1】:

    在表单对象中,声明字段的属性为readonly

    form.fields['field'].widget.attrs['readonly'] = True
    

    【讨论】:

    • 如果有人对该表单提出请求会发生什么? editable=False 更好?
    【解决方案2】:

    date 字段是表示条目首次创建的日期还是上次修改的日期?如果首先使用auto_now_add 选项,则使用auto_now。那就是:

    date = models.DateField(auto_now_add=True)
    

    将在创建条目时将date 设置为现在。

    auto_now_add 使字段不可编辑。对于其他情况,使用editable 选项使任何字段不可编辑。例如

    postedDate = models.TimeField(null=True, editable=False)
    

    此外,您可能会将posted 布尔字段添加到Entry 模型,因此在postedDate 上设置auto_now 很方便。每次修改条目时,它都会将 postedDate 设置为现在,包括将 posted 设置为 True 时的条目。

    【讨论】:

      【解决方案3】:

      我是这样实现的:https://djangosnippets.org/snippets/10514/ 此实现将模型实例的数据用于所有只读字段,而不是处理表单时获得的数据

      在相同的代码下,但使用他的例子

      from __future__ import unicode_literals
      
      from django.utils import six
      from django.utils.encoding import force_str
      
      __all__ = (
          'ReadOnlyFieldsMixin',
          'new_readonly_form_class'
      )
      
      
      class ReadOnlyFieldsMixin(object):
          """Usage:
          class MyFormAllFieldsReadOnly(ReadOnlyFieldsMixin, forms.Form):
              ...
      
      
          class MyFormSelectedFieldsReadOnly(ReadOnlyFieldsMixin, forms.Form):
              readonly_fields = ('field1', 'field2')
              ...
          """
          readonly_fields = ()
      
          def __init__(self, *args, **kwargs):
              super(ReadOnlyFieldsMixin, self).__init__(*args, **kwargs)
              self.define_readonly_fields(self.fields)
      
          def clean(self):
              cleaned_data = super(ReadOnlyFieldsMixin, self).clean()
      
              for field_name, field in six.iteritems(self.fields):
                  if self._must_be_readonly(field_name):
                      cleaned_data[field_name] = getattr(self.instance, field_name)
      
              return cleaned_data
      
          def define_readonly_fields(self, field_list):
      
              fields = [field for field_name, field in six.iteritems(field_list)
                        if self._must_be_readonly(field_name)]
      
              map(lambda field: self._set_readonly(field), fields)
      
          def _all_fields(self):
              return not bool(self.readonly_fields)
      
          def _set_readonly(self, field):
              field.widget.attrs['disabled'] = 'true'
              field.required = False
      
          def _must_be_readonly(self, field_name):
              return field_name in self.readonly_fields or self._all_fields()
      
      
      def new_readonly_form_class(form_class, readonly_fields=()):
          name = force_str("ReadOnly{}".format(form_class.__name__))
          class_fields = {'readonly_fields': readonly_fields}
          return type(name, (ReadOnlyFieldsMixin, form_class), class_fields)
      

      用法:

      class BlogEntry(models.Model):
          title = models.CharField(unique=True,max_length=50)
          description = models.TextField(blank=True)
          date = models.DateField(default=datetime.date.today)
          postedTime = models.TimeField(null=True)
      
      
      # all fields are readonly    
      class BlogEntryReadOnlyForm(ReadOnlyFieldsMixin, forms.ModelForm):
          class Meta:
              model = BlogEntry
      
      # selected fields are readonly
      class BlogEntryReadOnlyForm2(ReadOnlyFieldsMixin, forms.ModelForm):
          readonly_fields = ('date', 'postedTime')
          class Meta:
              model = BlogEntry
      

      或使用函数

      class BlogEntryForm(forms.ModelForm):
          class Meta:
              model = BlogEntry
      
      BlogEntryFormReadOnlyForm = new_readonly_form_class(BlogEntryForm, readonly_fields=('description', ))
      

      【讨论】:

        【解决方案4】:

        这将防止任何用户入侵请求:

        self.fields['is_admin'].disabled = True
        

        自定义表单示例:

        class MemberShipInlineForm(forms.ModelForm):
            is_admin = forms.BooleanField(required=False)
        
            def __init__(self, *args, **kwargs):
        
                super(MemberShipInlineForm, self).__init__(*args, **kwargs)
        
                if 'instance' in kwargs and kwargs['instance'].is_group_creator:
                    self.fields['is_admin'].disabled = True
        
            class Meta:
                model = MemberShip
                fields = '__all__'
        

        【讨论】:

          【解决方案5】:

          来自documentation

          class BlogEntryEditForm(ModelForm):
              class Meta:
              model = BlogEntry
              readonly_fields = ['date','postedTime']
          

          【讨论】:

          • 只是关于文档的问题。它说Any fields in this option (which should be a list or tuple) will display its data as-is and non-editable。我已经尝试过了,但我仍然可以单击文本字段并在其中输入内容。它实际上是如何工作的?
          • 这对 ModelForm 可行吗?我认为 'readonly_fields' 特定于 ModelAdmin docs.djangoproject.com/en/dev/ref/contrib/admin/…
          • 我认为 readonly_fields 是特定于管理员的,并且也在 django 1.2 中引入
          猜你喜欢
          • 1970-01-01
          • 2014-04-05
          • 2018-06-25
          • 1970-01-01
          • 1970-01-01
          • 2018-01-10
          • 2013-11-19
          • 2015-08-12
          • 2016-02-04
          相关资源
          最近更新 更多