我有一个带有多选字段的ModelForm。选择是属于特定俱乐部的徒步旅行者的填充实例。
我想通过在第1列包含复选框的表格中显示选项来自定义表单显示的方式,还有一些列显示每个hiker的详细信息。例如,列是(checboxes,名称,年龄,最喜欢的远足径)。
我不确定如何处理这个问题。如何使用模板中的关联模型实例字段访问和显示表单字段选项。有人知道Django这样做的方法吗?
#models.py
class Club(models.Model):
title = models.CharField()
hikers = models.ManyToManyField(Hikers)
class Hiker(models.Model):
name = models.CharField()
age = models.PositiveIntegerField()
favourite_trail = models.CharField()
#forms.py
class ClubForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
club_pk = kwargs['club_pk']
del kwargs['club_pk']
super(ClubForm, self).__init__(*args, **kwargs)
choices = [(ts.pk, ts.name) for hiker in Club.objects.filter(pk=club_pk)]
self.fields['hikers'].choices = choices
class Meta:
model = Club
fields = ('hikers',)
widgets = {'hikers': forms.CheckboxSelectMultiple}
答案 0 :(得分:37)
如果您在HTML模板中定义整个表单,则最简单。您应该能够在模板中迭代字段的值,如下所示:
{% for value, text in form.hikers.field.choices %}
{{ value }}: {{ text }}
{% endfor %}
答案 1 :(得分:10)
试试这个解决方案:
<ul>
{% for choice in form.my_choice_field.field.choices %}
<li>
<input type="radio" name="my_choice_field" value="{{choice.0}}"
{% ifequal form.my_choice_field.data choice.0 %}
checked="checked"
{% endifequal %}/>
<label for="">{{choice.1}}</label>
</li>
{% endfor %}
</ul>
请参阅此链接:http://www.ilian.io/django-forms-choicefield-and-custom-html-output/
答案 2 :(得分:8)
这非常棘手,但您可以使用ModelMultipleChoiceField
,CheckboxSelectMultiple
和自定义模板过滤器来完成此操作。表单和窗口小部件类大部分都在那里,但模板过滤器确定了哪个窗口小部件为您提供查询集中的每个实例。见下文......
# forms.py
from django import forms
from .models import MyModel
class MyForm(forms.Form):
my_models = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple,
queryset=None)
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.fields['my_models'].queryset = MyModel.objects.all()
# myapp/templatetags/myapp.py
from django import template
from copy import copy
register = template.Library()
@register.filter
def instances_and_widgets(bound_field):
"""Returns a list of two-tuples of instances and widgets, designed to
be used with ModelMultipleChoiceField and CheckboxSelectMultiple widgets.
Allows templates to loop over a multiple checkbox field and display the
related model instance, such as for a table with checkboxes.
Usage:
{% for instance, widget in form.my_field_name|instances_and_widgets %}
<p>{{ instance }}: {{ widget }}</p>
{% endfor %}
"""
instance_widgets = []
index = 0
for instance in bound_field.field.queryset.all():
widget = copy(bound_field[index])
# Hide the choice label so it just renders as a checkbox
widget.choice_label = ''
instance_widgets.append((instance, widget))
index += 1
return instance_widgets
# template.html
{% load myapp %}
<form method='post'>
{% csrf_token %}
<table>
{% for instance, widget in form.job_applications|instances_and_widgets %}
<tr>
<td>{{ instance.pk }}, {{ instance }}</td>
<td>{{ widget }}</td>
</tr>
{% endfor %}
</table>
<button type='submit' name='submit'>Submit</button>
</form>
如果您调整表单,它应该可以工作:
class ClubForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
cluk_pk = kwargs.pop('club_pk')
super(ClubForm, self).__init__(*args, **kwargs)
self.fields['hikers'].queryset = Club.objects.filter(pk=club_pk)
class Meta:
model = Club
fields = ('hikers',)
widgets = {'hikers': forms.CheckboxSelectMultiple}
答案 3 :(得分:1)
我认为,您可以使用自己的render()方法定义从CheckboxSelectMultiple继承的自己的widget类,并自定义html输出。 See source code, line 690
它也可以在任何模板中重复使用。
答案 4 :(得分:1)
这个答案提供了一个自定义表单小部件 - TableSelectMultiple
- 听起来像你想要的那样:
答案 5 :(得分:1)
相关票证:https://code.djangoproject.com/ticket/9230
我制作了一个制作这样一张桌子的小部件:http://skyl.org/log/post/skyl/2011/01/wherein-the-inner-workings-of-the-deathstarwidget-are-revealed/
我在这里寻找更好的解决方案:D
答案 6 :(得分:0)
通用解决方案的另一个示例:
{% for widget in form.field_name %}
<tr>
<th>
<label for="{{widget.id_for_label}}">
<input type="{{widget.data['type']}}" name="{{widget.data['name']}}" value="{{widget.data['value']}}" {% if widget.data['selected'] %}selected{% endif %} {% for k, v in widget.data['attrs'].items() %} {{k}}="{{v}}" {% endfor %}>
</label>
</th>
<td>
{{widget.choice_label}}
</td>
</tr>
{% endfor %}
说明:
基本上,您只需遍历form.field_name
,然后您会得到一个像这样的小部件:
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__html__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'choice_label', 'data', 'id_for_label', 'parent_widget', 'renderer', 'tag', 'template_name'] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__html__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'choice_label', 'data', 'id_for_label', 'parent_widget', 'renderer', 'tag', 'template_name']
其中widget.data
包含构建输入元素所需的所有信息:
{'name': 'field_name', 'value': 1, 'label': 'Field name 1', 'selected': False, 'index': '0', 'attrs': {'id': 'id_field_name_0'}, 'type': 'checkbox', 'template_name': 'django/forms/widgets/checkbox_option.html'}
答案 7 :(得分:0)
也许可以帮助某人。
template.html
<!-- radio -->
<div class="form-group">
{{ form.field_name.label_tag }}
{% for pk, choice in form.field_name.field.widget.choices %}
<div class="custom-control custom-radio custom-control-inline">
<input id="id_{{form.field_name.name}}_{{ forloop.counter0 }}" name="{{form.field_name.name}}" type="{{form.field_name.field.widget.input_type}}" value="{{pk}}" class="custom-control-input"
{% ifequal form.field_name.data pk.0 %}
checked="checked"
{% endifequal %}/>
<label for="id_{{form.field_name.name}}_{{ forloop.counter0 }}" class="custom-control-label">{{ choice }}</label>
</div>
{% endfor %}
</div>
<!-- checkbox -->
<div class="form-group">
{{ form.field_name.label_tag }}
{% for pk, choice in form.field_name.field.widget.choices %}
<div class="custom-control custom-checkbox custom-control-inline">
<input id="id_{{form.field_name.name}}_{{ forloop.counter0 }}" name="{{form.field_name.name}}" type="{{form.field_name.field.widget.input_type}}" value="{{pk}}" class="custom-control-input"
{% ifequal form.field_name.data pk.0 %}
checked="checked"
{% endifequal %}/>
<label for="id_{{form.field_name.name}}_{{ forloop.counter0 }}" class="custom-control-label">{{ choice }}</label>
</div>
{% endfor %}
</div>