在Django表单中,我如何使字段只读(或禁用)?

当使用表单创建新条目时,应该启用所有字段——但当记录处于更新模式时,某些字段需要为只读。

例如,当创建一个新的Item模型时,所有字段都必须是可编辑的,但是在更新记录时,是否有一种方法禁用sku字段,使其可见,但不能编辑?

class Item(models.Model):
    sku = models.CharField(max_length=50)
    description = models.CharField(max_length=200)
    added_by = models.ForeignKey(User)


class ItemForm(ModelForm):
    class Meta:
        model = Item
        exclude = ('added_by')

def new_item_view(request):
    if request.method == 'POST':
        form = ItemForm(request.POST)
        # Validate and save
    else:
            form = ItemForm()
    # Render the view

ItemForm类可以重用吗?ItemForm或Item模型类需要做哪些更改?我是否需要编写另一个类“ItemUpdateForm”来更新项目?

def update_item_view(request):
    if request.method == 'POST':
        form = ItemUpdateForm(request.POST)
        # Validate and save
    else:
        form = ItemUpdateForm()

当前回答

Django 1.9添加了Field。禁用属性:https://docs.djangoproject.com/en/stable/ref/forms/fields/#disabled

当disabled布尔参数设置为True时,使用disabled HTML属性禁用表单字段,以便用户不能编辑它。即使用户篡改了提交给服务器的字段值,它也会被忽略,而由表单初始数据的值代替。

其他回答

我也遇到了同样的问题,所以我创建了一个Mixin,它似乎适用于我的用例。

class ReadOnlyFieldsMixin(object):
    readonly_fields =()

    def __init__(self, *args, **kwargs):
        super(ReadOnlyFieldsMixin, self).__init__(*args, **kwargs)
        for field in (field for name, field in self.fields.iteritems() if name in self.readonly_fields):
            field.widget.attrs['disabled'] = 'true'
            field.required = False

    def clean(self):
        cleaned_data = super(ReadOnlyFieldsMixin,self).clean()
        for field in self.readonly_fields:
           cleaned_data[field] = getattr(self.instance, field)

        return cleaned_data

用法,只需定义哪些必须是只读的:

class MyFormWithReadOnlyFields(ReadOnlyFieldsMixin, MyForm):
    readonly_fields = ('field1', 'field2', 'fieldx')

对于Django 1.2+,你可以像这样重写字段:

sku = forms.CharField(widget = forms.TextInput(attrs={'readonly':'readonly'}))

一个简单的选择是在模板中输入form.instance.fieldName而不是form.fieldName。

由于我还不能评论(muhuk的解决方案),我将单独回答。这是一个完整的代码示例,适用于我:

def clean_sku(self):
  if self.instance and self.instance.pk:
    return self.instance.sku
  else:
    return self.cleaned_data['sku']

基于@paeduardo的回答(这是多余的),你可以在表单类初始化器中禁用一个字段:

class RecordForm(ModelForm):

     def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            var = self.fields['the_field']
            var.disabled = True