我现在每天都在使用Django三个月,这真的很棒。快速的Web应用程序开发。
我还有一件事我不能完全按照自己的意愿去做。 它是SelectField和SelectMultiple Field。
我希望能够将一些args放入Select的选项中。
我最终成功使用了optgroup:
class EquipmentField(forms.ModelChoiceField):
def __init__(self, queryset, **kwargs):
super(forms.ModelChoiceField, self).__init__(**kwargs)
self.queryset = queryset
self.to_field_name=None
group = None
list = []
self.choices = []
for equipment in queryset:
if not group:
group = equipment.type
if group != equipment.type:
self.choices.append((group.name, list))
group = equipment.type
list = []
else:
list.append((equipment.id, equipment.name))
但对于另一个ModelForm,我必须使用模型的color属性更改每个选项的背景颜色。
你知道我怎么做吗?
谢谢。
答案 0 :(得分:5)
您需要做的是更改由窗口小部件控制的输出。默认是选择小部件,因此您可以将其子类化。它看起来像这样:
class Select(Widget):
def __init__(self, attrs=None, choices=()):
super(Select, self).__init__(attrs)
# choices can be any iterable, but we may need to render this widget
# multiple times. Thus, collapse it into a list so it can be consumed
# more than once.
self.choices = list(choices)
def render(self, name, value, attrs=None, choices=()):
if value is None: value = ''
final_attrs = self.build_attrs(attrs, name=name)
output = [u'<select%s>' % flatatt(final_attrs)]
options = self.render_options(choices, [value])
if options:
output.append(options)
output.append('</select>')
return mark_safe(u'\n'.join(output))
def render_options(self, choices, selected_choices):
def render_option(option_value, option_label):
option_value = force_unicode(option_value)
selected_html = (option_value in selected_choices) and u' selected="selected"' or ''
return u'<option value="%s"%s>%s</option>' % (
escape(option_value), selected_html,
conditional_escape(force_unicode(option_label)))
# Normalize to strings.
selected_choices = set([force_unicode(v) for v in selected_choices])
output = []
for option_value, option_label in chain(self.choices, choices):
if isinstance(option_label, (list, tuple)):
output.append(u'<optgroup label="%s">' % escape(force_unicode(option_value)))
for option in option_label:
output.append(render_option(*option))
output.append(u'</optgroup>')
else:
output.append(render_option(option_value, option_label))
return u'\n'.join(output)
这是很多代码。但是你需要做的是用改变的渲染方法制作你自己的小部件。它是render方法,用于确定创建的html。在这种情况下,它是您需要更改的render_options
方法。在这里,您可以包含一些检查以确定何时添加一个可以设置样式的类。
另一件事,在你上面的代码中看起来并不像你追加最后一组选择。此外,您可能希望向查询集添加order_by()
,因为您需要按类型对其进行排序。您可以在init方法中执行此操作,因此在使用表单字段时无需执行此操作。
答案 1 :(得分:2)
render_option
已从Django 1.11开始删除。这就是我为实现这一目标所做的。一点点挖掘,这似乎简单明了。适用于Django 2.0 +
class CustomSelect(forms.Select):
def __init__(self, attrs=None, choices=()):
self.custom_attrs = {}
super().__init__(attrs, choices)
def create_option(self, name, value, label, selected, index, subindex=None, attrs=None):
index = str(index) if subindex is None else "%s_%s" % (index, subindex)
if attrs is None:
attrs = {}
option_attrs = self.build_attrs(self.attrs, attrs) if self.option_inherits_attrs else {}
if selected:
option_attrs.update(self.checked_attribute)
if 'id' in option_attrs:
option_attrs['id'] = self.id_for_label(option_attrs['id'], index)
# setting the attributes here for the option
if len(self.custom_attrs) > 0:
if value in self.custom_attrs:
custom_attr = self.custom_attrs[value]
for k, v in custom_attr.items():
option_attrs.update({k: v})
return {
'name': name,
'value': value,
'label': label,
'selected': selected,
'index': index,
'attrs': option_attrs,
'type': self.input_type,
'template_name': self.option_template_name,
}
class MyModelChoiceField(ModelChoiceField):
# custom method to label the option field
def label_from_instance(self, obj):
# since the object is accessible here you can set the extra attributes
if hasattr(obj, 'type'):
self.widget.custom_attrs.update({obj.pk: {'type': obj.type}})
return obj.get_display_name()
表格:
class BookingForm(forms.ModelForm):
customer = MyModelChoiceField(required=True,
queryset=Customer.objects.filter(is_active=True).order_by('name'),
widget=CustomSelect(attrs={'class': 'chosen-select'}))
我需要的输出是:
<select name="customer" class="chosen-select" required="" id="id_customer">
<option value="" selected="">---------</option>
<option value="242" type="CNT">AEC Transcolutions Private Limited</option>
<option value="243" type="CNT">BBC FREIGHT CARRIER</option>
<option value="244" type="CNT">Blue Dart Express Limited</option>
答案 2 :(得分:0)
您不应该使用表单字段来为渲染的html标记添加一些自定义属性。但是你应该将这些子类化并添加到Widget中。
来自docs: customizing-widget-instances
您可以将attrs
字典提交给窗体小部件,它在输出窗体小部件上呈现为属性。
class CommentForm(forms.Form):
name = forms.CharField(
widget=forms.TextInput(attrs={'class':'special'}))
url = forms.URLField()
comment = forms.CharField(
widget=forms.TextInput(attrs={'size':'40'}))
Django will then include the extra attributes in the rendered output:
>>> f = CommentForm(auto_id=False)
>>> f.as_table()
<tr><th>Name:</th><td><input type="text" name="name" class="special"/></td></tr>
<tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr>
答案 3 :(得分:0)
http://code.djangoproject.com/browser/django/trunk/django/newforms/widgets.py?rev=7083
如类选择(窗口小部件):所示,无法将样式属性添加到选项标记。为此,您必须继承此小部件并添加此类功能。
类选择(窗口小部件):定义仅将样式属性添加到主选择标记。
答案 4 :(得分:0)
通过
搜索时,我多次遇到这个问题“如何自定义/填充Django SelectField选项”
Dimitris Kougioumtzis提供的答案非常简单
希望它可以帮助像我这样的人。
# forms.py
from django.forms import ModelForm, ChoiceField
from .models import MyChoices
class ProjectForm(ModelForm):
choice = ChoiceField(choices=[
(choice.pk, choice) for choice in MyChoices.objects.all()])
# admin.py
class ProjectAdmin(BaseAdmin):
form = ProjectForm
....