我遇到一个简单的问题: 如何在通过modelForm和chooseFied在django Framework中生成的下拉菜单中有一些“禁用”字段?
目前,我无法弄清楚如何获得这样的输出: - 根1条目 - (禁用) - Elt 1 - (未禁用) - 根2条目 - (禁用)
你有什么建议吗?
皮尔
答案 0 :(得分:21)
Django的表单小部件提供了一种传递应该在<option>
标记上呈现的属性列表的方法:
my_choices = ( ('one', 'One'), ('two', 'Two'))
class MyForm(forms.Form):
some_field = forms.ChoiceField(choices=my_choices,
widget=forms.Select(attrs={'disabled':'disabled'}))
不幸的是,这对您不起作用,因为该属性将应用于呈现的每个选项标记。 Django无法自动知道哪些应该启用以及哪些应该被禁用。
在您的情况下,我建议您编写自定义小部件。这很容易做到,而且你没有那么多的自定义逻辑可以应用。关于此的文档是here。简而言之:
forms.Select
,这是默认的选择渲染器render(self, name, value, attrs)
方法。使用您的自定义逻辑来确定value
是否符合需要禁用的条件。如果您需要启发,请查看render
中django/forms/widgets.py
的非常短的实施情况。然后,定义表单字段以使用自定义窗口小部件:
class MyForm(forms.Form):
some_field = forms.ChoiceField(choices=my_choices,
widget=MyWidget)
答案 1 :(得分:5)
你可以像这样创建布莱恩所提到的选择。在以下选项Root 1中,Root 2会自动禁用,它们看起来像Group Options
CHOICES = (
('-- Root 1--',
(
('ELT1', 'ELT1'),
('ELT2', 'ELT2'),
('ELT3', 'ELT3'),
)
),
('-- Root 2--',
(
('ELT3', 'ELT3'),
('ELT4', 'ELT4'),
)
),
)
上面的选项会显示如下。在下图中,根1和根2不可选。
希望这能解决你的问题
-Vikram
答案 2 :(得分:4)
似乎django 1.1将允许“optgroup”:Django documentation
class MyForm(forms.Form):
some_field = forms.ChoiceField(choices=[
('Audio', (
('vinyl', 'Vinyl'),
('cd', 'CD'),
)
),
('Video', (
('vhs', 'VHS Tape'),
('dvd', 'DVD'),
)
),
('unknown', 'Unknown'),
])
这个imho是必须的。
答案 3 :(得分:3)
您是否尝试创建一个菜单,其中列表项被分为多个类别,并且您不希望类别本身可以选择?
如果是这样,您可以通过让模板使用标记渲染字段来实现此目的,例如
<select name="my_field" id="id_my_field">
<optgroup label="-- Root 1 entry --">
<option value="1">Elt 1</option>
<option value="2">Elt 2</option>
<option value="3">Elt 3</option>
</optgroup>
<optgroup label="--- Root 2 entry ---">
<option value="4">Elt 4</option>
<option value="5">Elt 5</option>
</optgroup>
</select>
答案 4 :(得分:3)
field_choices = (
('','Make choice'),
(1,'first'),
(2,'second'),
(3,'third')
)
from django.forms import Select
class Select(Select):
def create_option(self, *args,**kwargs):
option = super().create_option(*args,**kwargs)
if not option.get('value'):
option['attrs']['disabled'] = 'disabled'
if option.get('value') == 2:
option['attrs']['disabled'] = 'disabled'
return option
答案 5 :(得分:1)
这可能是一个迟到的答案,但这是一个可以使用表单实例修改的简化版本。
您可以传递要禁用的值列表,即
def __init__(self, disabled_choices, *args, **kwargs):
self.disabled_choices = disabled_choices
OR
from django.forms import Select
class SelectWidget(Select):
"""
Subclass of Django's select widget that allows disabling options.
"""
def __init__(self, *args, **kwargs):
self._disabled_choices = []
super(SelectWidget, self).__init__(*args, **kwargs)
@property
def disabled_choices(self):
return self._disabled_choices
@disabled_choices.setter
def disabled_choices(self, other):
self._disabled_choices = other
def create_option(self, name, value, label, selected, index, subindex=None, attrs=None):
option_dict = super(SelectWidget, self).create_option(
name, value, label, selected, index, subindex=subindex, attrs=attrs
)
if value in self.disabled_choices:
option_dict['attrs']['disabled'] = 'disabled'
return option_dict
根据条件禁用选项,即用户不是超级用户。
class MyForm(forms.Form):
status = forms.ChoiceField(required=True, widget=SelectWidget, choices=Status.choices())
def __init__(self, request, *args, **kwargs):
if not request.user.is_superuser:
self.fields['status'].widget.disabled_choices = [1, 4]
super().__init__(*args, **kwargs)
答案 6 :(得分:1)
在Django中,简单的问题有时会有复杂的答案。我花了很多时间使它运行良好。将Jarrett的概述与jnns关于render_option
的重要注释以及freenode上#django的一些帮助相结合,我得到了一个运行良好的完整示例解决方案:
首先,此示例假定在我称为Rule的模型中具有通常定义的选择类型CharField。我将自己的TimeStampedModel
子类化,但是您可以使用models.Model
:
class Rule(TimeStampedModel):
...
# Rule Type
SHORT_TERM_RULE = 'ST'
MAX_SIGHTINGS_PER_PERIOD_RULE = "MA"
WHITE_LIST_RULE = "WL"
BLACK_LIST_RULE = "BL"
RULE_CHOICES = (
(SHORT_TERM_RULE, 'Short Term Rule'),
(MAX_SIGHTINGS_PER_PERIOD_RULE, 'Max Sightings Per Period Rule'),
(WHITE_LIST_RULE, 'White List Rule'),
(BLACK_LIST_RULE, 'Black List Rule'),
)
rule_type = models.CharField(
max_length=2,
choices=RULE_CHOICES,
default=SHORT_TERM_RULE,
)
...
在forms.py中,定义接受Select
的窗口小部件子类disabled_choices
。它有一个自定义render_option()
,如果在disabled
列表中包含选项,则将disabled_choices
添加到选项标签的html输出中。请注意,我按原样保留了render_option()
的大部分Select
代码:
class MySelect(Select):
def __init__(self, attrs=None, choices=(), disabled_choices=()):
super(MySelect, self).__init__(attrs, choices=choices)
self.disabled_choices = disabled_choices
def render_option(self, selected_choices, option_value, option_label):
if option_value is None:
option_value = ''
option_value = force_text(option_value)
if option_value in selected_choices:
selected_html = mark_safe(' selected="selected"')
if not self.allow_multiple_selected:
selected_choices.remove(option_value)
else:
selected_html = ''
for key, value in self.disabled_choices:
if option_value in key:
return format_html('<option disabled value="{}"{}>{}</option>', option_value, selected_html,
force_text(option_label))
return format_html('<option value="{}"{}>{}</option>', option_value, selected_html, force_text(option_label))
然后,在定义表单子类ModelForm
的过程中,检查传入的disabled_choices
列表并相应地初始化该字段。在此示例中,我还潜入了默认选择。
class RuleChoiceForm(ModelForm):
class Meta:
model = Rule
fields = ['rule_type']
# Add a default choice to the list defined in the Rule model
default_choice = ('DF', 'Choose a Rule Type...')
choices = list(Rule.RULE_CHOICES)
choices.insert(0, default_choice)
choices = tuple(choices)
rule_type = forms.ChoiceField(widget=MySelect(attrs={'class': 'form-control'}, disabled_choices=[]),
choices=choices)
def __init__(self, *args, disabled_choices=None, **kwargs):
super(RuleChoiceForm, self).__init__(*args, **kwargs)
if disabled_choices:
self.fields['rule_type'].widget.disabled_choices = disabled_choices
然后在您的视图中,将disabled_choices
定义为列表,在模型中将_CHOICES
变量中的选择追加到模型中。按照我的逻辑,我使用RULE_CHOICES
的列表理解来获取要禁用的选择的元组。尽管可能有更简单的方法,但请随时发布建议以简化或改进此答案。
disabled_choices = []
# Logic disabling choices
if Rule.objects.filter(route=route, rule_type=Rule.SHORT_TERM_RULE).exists():
disabled_choices.append([item for item in Rule.RULE_CHOICES if Rule.SHORT_TERM_RULE in item][0])
disabled_choices.append([item for item in Rule.RULE_CHOICES if Rule.MAX_SIGHTINGS_PER_PERIOD_RULE in item][0])
rule_choice_form = RuleChoiceForm(disabled_choices=disabled_choices)