Как получить экземпляры ModelChoiceField в шаблоне

У меня есть ModelForm, который содержит ModelChoiceField с помощью виджета RadioSelect.

<code>class MyAForm(forms.ModelForm):
    one_property = models.ModelChoiceField(
        widget=forms.RadioSelect,
        queryset=MyBModel.objects.filter(visible=True),
        empty_label=None)
    class Meta:
        model = MyAModel
</code>

В MyBModel есть атрибуты, которые я хочу отобразить рядом с переключателем. Я бы переопределилlabel_from_instance в подклассе ModelChoiceField, но это не позволяет мне делать то, что я хочу, так как я хочу, чтобы переключатель отображался внутри таблицы, в которой есть строка для каждого элемента выбора.

Так что где-то в моем шаблоне я хочу что-то вроде ...

<code>{% for field in form.visible_fields %}
    {% if field.name == "one_property" %}
    <table>
        {% for choice in field.choices %}
            <tr>
                <td><input value="{{choice.id}}" type="radio" name="one_property" />{{choice.description}}</td>
                <td><img src="{{choice.img_url}}" /></td>
            </tr>
        {% endfor %}
    </table>
    {% endif %}
{% endfor %}
</code>

К сожалению, field.choices возвращает кортеж с идентификатором объекта и меткой, а не с экземпляром из набора запросов.

Есть ли простой способ получить экземпляры выбора для ModelChoiceField для использования в шаблоне?

Ответы на вопрос(3)

Я хотел сделать что-то, почти идентичное вопросу OP (таблица и все), так же был разочарован отсутствием сотрудничества с Django и так же закончил тем, что углубился в источник, чтобы придумать мою собственную реализацию. То, что я придумал, немного отличается от принятого ответа, и мне понравилось больше, потому что я использовал простой{{ form.as_table }} в моем шаблоне и не хотите, чтобы пройти черезvisible_fields без необходимости или жестко закодировать переключатель в моем шаблоне, который просто выглядит как текущая реализация Django (которая может измениться). Вот что я сделал вместо этого:

RadioInput and RadioFieldRenderer

Джанго & APOS; sRadioSelect виджет используетRadioFieldRenderer датьгенератор изRadioInputs, которые делают фактическую работу рендеринга переключателей.RadioSelect похоже, имеется недокументированная функция, в которой вы можете передать ему средство рендеринга, отличное от этого по умолчанию, поэтому вы можете создать подкласс обоих, чтобы получить то, что хочет OP.

from django import forms
from django.utils.safestring import mark_safe

class CustomTableRadioInput(forms.widgets.RadioInput):

    # We can override the render method to display our table rows
    def render(self, *args, **kwargs):
        # default_html will hold the normally rendered radio button
        # which we can then use somewhere in our table
        default_html = super(CustomTableRadioInput, self).render(*args, **kwargs)
        # Do whatever you want to the input, then return it, remembering to use
        # either django.utils.safestring.mark_safe or django.utils.html.format_html
        # ...
        return mark_safe(new_html)

class CustomTableFieldRenderer(forms.widget.RadioFieldRenderer):
    # Here we just need to override the two methods that yield RadioInputs
    # and make them yield our custom subclass instead
    def __iter__(self):
        for i, choice in enumerate(self.choices):
            yield CustomTableRadioInput(self.name, self.value,
                                          self.attrs.copy(), choice, i)

    def __getitem__(self, idx):
        choice = self.choices[idx] # Let the IndexError propogate
        return CustomTableRadioInput(self.name, self.value,
                                       self.attrs.copy(), choice, idx)

После этого нам просто нужно сказатьRadioSelect виджет для использования нашего пользовательского рендерера всякий раз, когда мы вызываем его где-нибудь в нашем коде формы:

...
radio = forms.ChoiceField(widget=forms.RadioSelect(renderer=CustomTableFieldRenderer),
                          choices=...)
...

И это все!

Обратите внимание, что для использования этого в шаблоне вы, вероятно, захотите перебрать поле, а не вызывать его напрямую, то есть это:

<table>
  <tbody>
  {% for tr in form.radio %}
    <tr>{{ tr }}</tr>
  {% endfor %}
  </tbody>
</table>

а не это:

<table>
  <tbody>{{ form.radio }}</tbody>
</table>

Если вы сделаете последнее, он попытается обернуть элементы таблицы в<ul><li>...</li></ul>.

Решение Вопроса

Изучив исходный код django для ModelChoiceField, я обнаружил, что у него есть свойство "queryset".

Я смог использовать что-то вроде ...

{% for field in form.visible_fields %}
    {% if field.name == "one_property" %}
    <table>
        {% for choice in field.queryset %}
            <tr>
                <td><input value="{{choice.id}}" type="radio" name="one_property" />{{choice.description}}</td>
                <td><img src="{{choice.img_url}}" /></td>
            </tr>
        {% endfor %}
    </table>
    {% endif %}
{% endfor %}
 18 мар. 2018 г., 03:38
Это не сработало для меня - может, Джанго изменился?
 Stephen Paulger11 окт. 2012 г., 11:17
У вас есть один = это должно быть ==
 29 янв. 2019 г., 02:13
Я надеюсь, что вы запустите стартап и получите многомиллионный выход всего за 2 года. Мучо Appriciato!
 10 окт. 2012 г., 13:25
Привет, если я распечатал это{{field.name}} затем он печатает все имена полей, но если я использовал его в условии `{% if field.name = & quot; attribute & quot; %} `или` {% if field.name = attribute%} `и попытайтесь напечатать что-либо при превышении этого условия, а затем ничего не печатать, значит условие возвращает false Но имя поля, которое я использовал в этом условии, это то, которое оно печатает .. ** ПОЧЕМУ ТАК ?? **

Обычно вам нужен не сам объект, а его воспроизведение.

Рассмотрим этот код:

class LabelledHiddenWidget(forms.HiddenInput):

    def __init__(self, get_object, *args, **kwargs):
        super(LabelledHiddenWidget, self).__init__(*args, **kwargs)
        self.get_object = get_object

    def render(self, name, value, attrs=None):
        s = super(LabelledHiddenWidget, self).render(name, value, attrs)
        if value:
            s += SafeUnicode("<span>%s</span>" % self.get_object(value))
        return s

Тогда вы можете использовать это так:

class SomeForm(forms.Form):
    object = forms.ModelChoiceField(
         SomeModel.objects.all(), 
         widget=LabelledHiddenWidget(get_object=lambda id: get_object_or_404(SomeModel, id=id)))

Затем в коде шаблона,{{ form.object }} выведет скрытое поле с идентификатором объекта, соединенным с некоторой меткой. Конечно, ваш SomeModel должен реализовать__unicode__ или какой-то другой метод, который возвращает хороший, читаемый человеком ярлык.

Ваш ответ на вопрос