У меня есть ModelForm с полем множественного выбора. Выбор - это заполненные экземпляры Hikers, принадлежащие определенному Клубу.
Я хочу настроить способ отображения моей формы, показывая варианты в таблице, где в первом столбце содержатся флажки, а еще несколько столбцов отображают детали каждого туриста. Так, например, столбцы (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}
Ответ 1
Проще всего было бы, если бы вы определили всю форму в HTML-шаблоне. Вы должны иметь возможность перебирать значения полей в шаблоне следующим образом:
{% for value, text in form.hikers.field.choices %}
{{ value }}: {{ text }}
{% endfor %}
Ответ 2
Попробуйте это решение:
<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/
Ответ 3
Это удивительно сложно, но вы можете сделать это с помощью 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}
Ответ 4
Я думаю, вы можете определить собственный класс виджетов, унаследованный от CheckboxSelectMultiple, с помощью собственного метода render() и настроить вывод html.
См. исходный код, строка 690
Он будет использоваться повторно в любом шаблоне.
Ответ 5
Этот ответ предоставляет настраиваемый виджет формы - TableSelectMultiple
- который звучит так, как вы хотите:
Здесь также оригинальный фрагмент Django.
Ответ 6
связанный билет: https://code.djangoproject.com/ticket/9230
Я создал виджет, который создает такую таблицу: http://skyl.org/log/post/skyl/2011/01/wherein-the-inner-workings-of-the-deathstarwidget-are-revealed/
Теперь я ищу лучшее решение: D
Ответ 7
Другой пример универсального решения (только шаблон):
{% 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'}
Ответ 8
Может быть, помочь кому-то.
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>
Как настроить флажок и радио в Django с помощью Bootstrap
![My result]()