e70*_*e70 403 forms django field readonly
在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
Run Code Online (Sandbox Code Playgroud)
班级ItemForm
可以重复使用吗?ItemForm
或者Item
模型类需要进行哪些更改?我是否需要编写另一个类" ItemUpdateForm
"来更新项目?
def update_item_view(request):
if request.method == 'POST':
form = ItemUpdateForm(request.POST)
# Validate and save
else:
form = ItemUpdateForm()
Run Code Online (Sandbox Code Playgroud)
Dan*_*aab 399
正如在这个答案中指出的,Django 1.9添加了Field.disabled属性:
禁用的boolean参数设置为True时,将使用禁用的HTML属性禁用表单字段,以便用户无法编辑它.即使用户篡改了提交给服务器的字段值,也会忽略该表单的初始数据中的值.
使用Django 1.8及更早版本,要禁用小部件上的条目并防止恶意POST黑客,除了readonly
在表单字段上设置属性外,还必须擦除输入:
class ItemForm(ModelForm):
def __init__(self, *args, **kwargs):
super(ItemForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
if instance and instance.pk:
self.fields['sku'].widget.attrs['readonly'] = True
def clean_sku(self):
instance = getattr(self, 'instance', None)
if instance and instance.pk:
return instance.sku
else:
return self.cleaned_data['sku']
Run Code Online (Sandbox Code Playgroud)
或者,替换if instance and instance.pk
为表示您正在编辑的其他条件.您也可以disabled
在输入字段上设置属性,而不是readonly
.
该clean_sku
函数将确保该readonly
值不会被a覆盖POST
.
否则,没有内置的Django表单字段,它将在拒绝绑定的输入数据时呈现值.如果这是你想要的,你应该创建一个单独的ModelForm
排除不可编辑的字段,然后在模板中打印它们.
Mik*_*mud 166
Django 1.9添加了Field.disabled属性:https://docs.djangoproject.com/en/stable/ref/forms/fields/#disabled
禁用的boolean参数设置为True时,将使用禁用的HTML属性禁用表单字段,以便用户无法编辑它.即使用户篡改了提交给服务器的字段值,也会忽略该表单的初始数据中的值.
muh*_*huk 93
在窗口小部件上设置READONLY只会使浏览器中的输入为只读.添加返回instance.sku的clean_sku可确保字段值不会在表单级别上更改.
def clean_sku(self):
if self.instance:
return self.instance.sku
else:
return self.fields['sku']
Run Code Online (Sandbox Code Playgroud)
这样您就可以使用模型(未修改的保存)和aviod获取字段所需的错误.
chi*_*ale 63
awalker的答案对我帮助很大!
我使用get_readonly_fields改变了他的例子以使用Django 1.3 .
通常你应该声明这样的东西app/admin.py
:
class ItemAdmin(admin.ModelAdmin):
...
readonly_fields = ('url',)
Run Code Online (Sandbox Code Playgroud)
我用这种方式改编:
# In the admin.py file
class ItemAdmin(admin.ModelAdmin):
...
def get_readonly_fields(self, request, obj=None):
if obj:
return ['url']
else:
return []
Run Code Online (Sandbox Code Playgroud)
它工作正常.现在,如果添加一个Item,则该url
字段为读写,但在更改时,它将变为只读.
Hum*_*rey 53
要使其适用于ForeignKey字段,需要进行一些更改.首先,SELECT HTML标记没有readonly属性.我们需要使用disabled ="disabled".但是,浏览器不会为该字段发回任何表单数据.因此,我们需要将该字段设置为不需要,以便字段正确验证.然后,我们需要将值重置为以前的值,因此不会将其设置为空白.
因此,对于外键,您需要执行以下操作:
class ItemForm(ModelForm):
def __init__(self, *args, **kwargs):
super(ItemForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
if instance and instance.id:
self.fields['sku'].required = False
self.fields['sku'].widget.attrs['disabled'] = 'disabled'
def clean_sku(self):
# As shown in the above answer.
instance = getattr(self, 'instance', None)
if instance:
return instance.sku
else:
return self.cleaned_data.get('sku', None)
Run Code Online (Sandbox Code Playgroud)
这样浏览器就不会让用户更改字段,并且总是POST,因为它保留为空白.然后,我们覆盖clean方法,将字段的值设置为最初在实例中的值.
Ste*_*Nch 25
对于Django 1.2+,您可以像这样覆盖该字段:
sku = forms.CharField(widget = forms.TextInput(attrs={'readonly':'readonly'}))
Run Code Online (Sandbox Code Playgroud)
chr*_*e31 16
我创建了一个可以继承的MixIn类,以便能够添加一个read_only可迭代字段,该字段将禁用非安全字段上的字段并保护字段:
(基于Daniel和Muhuk的答案)
from django import forms
from django.db.models.manager import Manager
# I used this instead of lambda expression after scope problems
def _get_cleaner(form, field):
def clean_field():
value = getattr(form.instance, field, None)
if issubclass(type(value), Manager):
value = value.all()
return value
return clean_field
class ROFormMixin(forms.BaseForm):
def __init__(self, *args, **kwargs):
super(ROFormMixin, self).__init__(*args, **kwargs)
if hasattr(self, "read_only"):
if self.instance and self.instance.pk:
for field in self.read_only:
self.fields[field].widget.attrs['readonly'] = "readonly"
setattr(self, "clean_" + field, _get_cleaner(self, field))
# Basic usage
class TestForm(AModelForm, ROFormMixin):
read_only = ('sku', 'an_other_field')
Run Code Online (Sandbox Code Playgroud)
小智 10
我遇到了类似的问题.看起来我能够通过在我的ModelAdmin类中定义"get_readonly_fields"方法来解决它.
像这样的东西:
# In the admin.py file
class ItemAdmin(admin.ModelAdmin):
def get_readonly_display(self, request, obj=None):
if obj:
return ['sku']
else:
return []
Run Code Online (Sandbox Code Playgroud)
好的是,obj
当您添加新项时,它将是None,或者当您更改现有项时,它将是正在编辑的对象.
这里记录了get_readonly_display:http://docs.djangoproject.com/en/1.2/ref/contrib/admin/#modeladmin-methods
Dan*_*ple 10
我刚刚为readonly字段创建了最简单的小部件 - 我真的不明白为什么表单没有这个:
class ReadOnlyWidget(widgets.Widget):
"""Some of these values are read only - just a bit of text..."""
def render(self, _, value, attrs=None):
return value
Run Code Online (Sandbox Code Playgroud)
形式如下:
my_read_only = CharField(widget=ReadOnlyWidget())
Run Code Online (Sandbox Code Playgroud)
很简单 - 让我只输出.在一个带有一堆只读值的formset中得心应手.当然 - 你也可以更聪明一点,给它一个带有attrs的div,这样你就可以为它添加类.
我如何使用 Django 1.11 做到这一点:
class ItemForm(ModelForm):
disabled_fields = ('added_by',)
class Meta:
model = Item
fields = '__all__'
def __init__(self, *args, **kwargs):
super(ItemForm, self).__init__(*args, **kwargs)
for field in self.disabled_fields:
self.fields[field].disabled = True
Run Code Online (Sandbox Code Playgroud)
再一次,我将提供另一种解决方案:) 我使用的是汉弗莱的代码,所以这是基于此的。
但是,我遇到了该字段为ModelChoiceField
. 一切都会在第一个请求上工作。但是,如果表单集尝试添加新项目但验证失败,则“现有”表单出现问题,其中SELECTED
选项被重置为默认---------
.
无论如何,我无法弄清楚如何解决这个问题。所以相反,(我认为这实际上在形式上更清晰),我制作了 fields HiddenInputField()
。这只是意味着您必须在模板中做更多的工作。
所以我的解决方法是简化表格:
class ItemForm(ModelForm):
def __init__(self, *args, **kwargs):
super(ItemForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
if instance and instance.id:
self.fields['sku'].widget=HiddenInput()
Run Code Online (Sandbox Code Playgroud)
因此,在这种情况下,您将在模板中执行以下操作:
<div>
{{ form.instance.sku }} <!-- This prints the value -->
{{ form }} <!-- Prints form normally, and makes the hidden input -->
</div>
Run Code Online (Sandbox Code Playgroud)
这对我来说效果更好一点,而且表单操作更少。
您可以在小部件中优雅地添加只读:
class SurveyModaForm(forms.ModelForm):
class Meta:
model = Survey
fields = ['question_no']
widgets = {
'question_no':forms.NumberInput(attrs={'class':'form-control','readonly':True}),
}
Run Code Online (Sandbox Code Playgroud)
作为Humphrey帖子的有用补充,我在django-reversion中遇到了一些问题,因为它仍然将禁用的字段注册为"已更改".以下代码修复了该问题.
class ItemForm(ModelForm):
def __init__(self, *args, **kwargs):
super(ItemForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
if instance and instance.id:
self.fields['sku'].required = False
self.fields['sku'].widget.attrs['disabled'] = 'disabled'
def clean_sku(self):
# As shown in the above answer.
instance = getattr(self, 'instance', None)
if instance:
try:
self.changed_data.remove('sku')
except ValueError, e:
pass
return instance.sku
else:
return self.cleaned_data.get('sku', None)
Run Code Online (Sandbox Code Playgroud)
小智 5
由于我还不能评论(muhuk的解决方案),我会作为一个单独的答案作出回应.这是一个完整的代码示例,对我有用:
def clean_sku(self):
if self.instance and self.instance.pk:
return self.instance.sku
else:
return self.cleaned_data['sku']
Run Code Online (Sandbox Code Playgroud)
我遇到了同样的问题,所以我创建了一个似乎适合我的用例的 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
Run Code Online (Sandbox Code Playgroud)
用法,只需定义哪些必须是只读的:
class MyFormWithReadOnlyFields(ReadOnlyFieldsMixin, MyForm):
readonly_fields = ('field1', 'field2', 'fieldx')
Run Code Online (Sandbox Code Playgroud)
对于 django 1.9+,
您可以使用 Fields disabled 参数来禁用字段。例如,在下面来自 forms.py 文件的代码片段中,我禁用了 employee_code 字段
class EmployeeForm(forms.ModelForm):
employee_code = forms.CharField(disabled=True)
class Meta:
model = Employee
fields = ('employee_code', 'designation', 'salary')
Run Code Online (Sandbox Code Playgroud)
参考 https://docs.djangoproject.com/en/dev/ref/forms/fields/#disabled
归档时间: |
|
查看次数: |
249049 次 |
最近记录: |