Django: как отобразить мои собственные динамически созданные поля - PullRequest
0 голосов
/ 23 января 2020

У меня есть SurveyForm, где я динамически создаю свои поля. Вот самый базовый c код, который я мог сделать, и у меня все еще есть проблема:

class SurveyForm(forms.Form):

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

        self.fields = []
        self.fields_alone = []
        new_field = forms.CharField(label=f'1 - 2: This is the question',
                                    widget=widgets.Input(attrs={}))
        self.fields.append(('id_1', new_field))
        self.fields_alone.append(new_field)
        self.fields = OrderedDict(self.fields)

В моем шаблоне, когда я делаю «классический» l oop, я могу отобразить поля, и это работает, но второй l oop, который должен иметь доступ к тем же полям, не работает:

<form action="" method="post">
    {% for field in form %}
        {{ field.label }}&nbsp;:{{ field }} <br>
    {% endfor %}

    {% for field in form.fields_alone %}
        {{ field.label }}&nbsp;:{{ field }} <br>
    {% endfor %}
</form>

Второй l oop отображает поле в виде строки типа <django.forms.fields.CharField object at 0x0000012C00EF60D0>

То, что мне не хватает для отображения, похоже на «классический» l oop?

Ответы [ 3 ]

0 голосов
/ 23 января 2020

Здесь:

self.fields = []

Вы перезаписываете собственный fields заказанный приговор формы. Вы просто хотите добавить к нему:

self.fields["whatevernameyouwant"] = new_field

(работает на django 1.11, не тестировалось на 2.x / 3.x)

EDIT :

проблема в том, что я пытаюсь использовать поля через другое свойство

Вы имеете в виду вещь form.fields_alone? Ну, вы всегда можете сделать это property вместо этого:

class YourForm(...):
    def __init__(...)
        # ....
        self._fields_alone = []
        self.fields["whatevernameyouwant"] = new_field
        self.fields_alone.append("whatevernameyouwant")

    @property
    def fields_alone(self):
        for name in self._fields_alone:
            yield self[name]

Но это не удалит это поле из "обычного" итератора формы (for field in form), поэтому у вас будет поле дважды поэтому вам также нужно переопределить __iter__:

def __iter__(self):
    for name in self.fields:
        if name not in self._fields_alone:
            yield self[name]
0 голосов
/ 24 января 2020

Я нашел проблему. Он находится в исходном коде Django.

Django может конвертировать поля в HTML, только если они BoundField. Проблема в том, что вы можете получить доступ к BoundField "версии" полей вашей формы с помощью итерации в самой форме .

В django/forms/forms.py:

def __getitem__(self, name):
    # blabla code
    if name not in self._bound_fields_cache:
        self._bound_fields_cache[name] = field.get_bound_field(self, name)

Таким образом, вы можете получить HTML код только через итерацию в форме или прямой доступ к полю через form['myfield'].

Итак, в своей форме я сделал:

class SurveyForm(forms.Form):
    def field_by_id(self, field_id):
        return self[field_id]

Затем я сделал в своем приложении тег шаблона:

@register.filter(name='field_by_id')
def field_by_id(arg1, arg2):
    """
    Returns the result of field_by_id() (= method has to exist in arg1!)
    Usage: {{ form|field_by_id:XXX }} (XXX = field id string)

    :param arg1: object of class Form
    :param arg2: field id string
    :returns corresponding field
    """
    return arg1.field_by_id(arg2)

, а затем в своем шаблоне я использую его так:

    {% for question_group, questions in form.question_groups.items %}
        {% for question, answers in questions.items %}
            {% for answer in answers %}
                {% with form|field_by_id:answer as field %}
                    {{ field.label }}&nbsp;:{{ field }} <br>
                {% endwith %}
            {% endfor %}
        {% endfor %}
    {% endfor %}

И это работает , Сложное решение, но у меня много подгрупп (я мог бы использовать FormSet для одной подгруппы).

0 голосов
/ 23 января 2020

Список fields предназначен для хранения полей формы. Принимая во внимание, что fields_alone не является.

Это также причина, по которой вы можете l oop над самой формой, а не над form.fields.

, поскольку я не могу понять, почему вам нужен этот другой список, я предлагаю вам добавить все поля в фактический список fields.

Прокомментируйте, если есть какие-либо дополнительные вопросы к этой проблеме

...