Python 如何循环表单字段选择并显示关联的模型实例字段
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4437386/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to loop over form field choices and display associated model instance fields
提问by sizeight
I have a ModelForm with a multiple choice field. The choices are populated instances of Hikers belonging to a specific Club.
我有一个带有多项选择字段的 ModelForm。这些选择是属于特定俱乐部的徒步旅行者的填充实例。
I want to customize the way my form displays, by displaying the choices in a table where the 1st column contains checkboxes, and a few more columns display the details of each hiker. So for example the columns are (checboxes, name, age, favourite hiking trail).
我想自定义表单的显示方式,方法是在表格中显示选项,其中第一列包含复选框,另外几列显示每个徒步旅行者的详细信息。例如,列是(复选框、姓名、年龄、最喜欢的远足径)。
I'm not sure how to approach this. How do I access and display the form field choices with it's associated model instance fields in my template. Anybody know of the Django way to do this?
我不知道如何解决这个问题。如何访问和显示表单字段选项及其模板中关联的模型实例字段。有人知道 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}
采纳答案by Bernhard Vallant
Easiest would be if you define the whole form in a HTML template. You should be able to iterate over a field's values in a template like that:
最简单的方法是在 HTML 模板中定义整个表单。您应该能够像这样在模板中迭代字段的值:
{% for value, text in form.hikers.field.choices %}
{{ value }}: {{ text }}
{% endfor %}
回答by Alexey
I think, you can define own widget class inherited from CheckboxSelectMultiple with your own render() method and customize html output. See source code, line 690
我认为,您可以使用自己的 render() 方法定义从 CheckboxSelectMultiple 继承的自己的小部件类并自定义 html 输出。 参见源代码,第 690 行
It'll be reusable in any template as well.
它也可以在任何模板中重复使用。
回答by Jonny Buchanan
This answer provides a custom form widget - TableSelectMultiple- which sounds like what you want:
这个答案提供了一个自定义表单小部件 - TableSelectMultiple- 这听起来像你想要的:
There's also the original Django Snippet.
回答by Skylar Saveland
related ticket: https://code.djangoproject.com/ticket/9230
相关票证:https: //code.djangoproject.com/ticket/9230
I made a widget that makes such a table: http://skyl.org/log/post/skyl/2011/01/wherein-the-inner-workings-of-the-deathstarwidget-are-revealed/
我制作了一个制作这样一张桌子的小部件:http: //skyl.org/log/post/skyl/2011/01/wherein-the-inner-workings-of-the-deathstarwidget-are-revealed/
I'm here looking for a better solution still though :D
我仍然在这里寻找更好的解决方案:D
回答by seddonym
This is surprisingly tricky, but you can do it using ModelMultipleChoiceField, CheckboxSelectMultiple, and a custom template filter. The form and widget classes get most of the way there, but the template filter works out which widget to give you for each instance in the queryset. See below...
这是令人惊讶的棘手,但你可以用它做的ModelMultipleChoiceField,CheckboxSelectMultiple和自定义模板过滤器。表单和小部件类在那里完成大部分工作,但模板过滤器会为查询集中的每个实例计算出为您提供的小部件。见下文...
Generic solution
通用解决方案
# 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>
Specific to you
具体到你
It should work if you adjust the form like so:
如果您像这样调整表单,它应该可以工作:
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}
回答by Armance
Try this solution :
试试这个解决方案:
<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>
see this link : http://www.ilian.io/django-forms-choicefield-and-custom-html-output/
请参阅此链接:http: //www.ilian.io/django-forms-choicefield-and-custom-html-output/
回答by Jahid
Another example of a generic solution (template only):
通用解决方案的另一个示例(仅限模板):
{% 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 %}
Explanation:
解释:
Basically, you just iterate over form.field_nameand there you get an widget like this:
基本上,您只需重复一遍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']
where widget.datacontains all the needed info to build the input elements:
其中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'}
回答by Clebiano da Costa Sá
Maybe help someone.
也许帮助某人。
template.html
模板.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>
How to custom checkbox and radio in Django using Bootstrap


