【问题标题】:Django: how to display my own dynamically-made fieldsDjango:如何显示我自己的动态字段
【发布时间】:2020-05-09 18:12:36
【问题描述】:

我有一个SurveyForm,我可以在其中动态创建我的字段。这是我可以做的最基本的代码,但仍然有我的问题:

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)

在我的模板中,当我执行“经典”循环时,我可以显示字段并且它可以工作,但是应该访问相同字段的第二个循环不起作用:

<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>

第二个循环将字段显示为字符串,如&lt;django.forms.fields.CharField object at 0x0000012C00EF60D0&gt;

我缺少显示的类似于“经典”循环的内容?

【问题讨论】:

    标签: django django-forms django-templates


    【解决方案1】:

    我发现了问题。它在 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)
    

    因此,您只能通过表单上的迭代或通过form['myfield'] 直接访问字段来获取 HTML 代码。

    所以以我的形式我做到了:

    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 用于单个子组)。

    【讨论】:

      【解决方案2】:

      fields 列表用于存储表单字段。而fields_alone 不是。

      这也是您能够循环遍历表单本身而不是遍历form.fields 的原因。

      由于我无法弄清楚您为什么需要这个其他列表,我建议您将所有字段添加到实际的 fields 列表中。

      如果对此问题还有其他问题,请发表评论

      【讨论】:

      • 我需要创建并显示一个 100% 动态构建的表单,其中包含按“问题”分组的“答案”和按“问题组”分组的“问题”和按“问题组”分组的字段通过我自己的“形式”模型。为了做到这一点,我试图根据这个来制作我的代码:stackoverflow.com/questions/10366745/django-form-field-grouping
      • ...为了能够做到这一点,我不知道如何制作“递归”组的字段组(等等)
      【解决方案3】:

      这里:

      self.fields = []
      

      您正在覆盖表单自己的fieldsordereddict。您只想添加:

      self.fields["whatevernameyouwant"] = new_field
      

      (适用于 django 1.11,未在 2.x / 3.x 上测试)

      编辑

      问题是当我尝试通过另一个属性使用字段时

      你的意思是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]
      

      【讨论】:

      • 嗨。我已经做了很多次了,它完美地工作,问题是当我尝试通过 another 属性使用字段时。
      • 嗨,你的解决方案也不起作用......但是在模板中我更容易地重现了这个问题,如果这可以帮助你......帮助我:{% for field in form.fields.values %} {{ field.label }}&amp;nbsp;:{{ field }} &lt;br&gt; {% endfor %} -->这将显示 &lt;django.forms.fields.CharField object at 0x0000012C00EF60D0&gt; 之类的内容,而不是实际字段
      • 真正让我不安的是{{ field.label }} 在两个循环中都能正常工作。这是{{ field }}“单独”不起作用。
      猜你喜欢
      • 2019-05-02
      • 2010-10-28
      • 2011-10-05
      • 1970-01-01
      • 1970-01-01
      • 2021-05-24
      • 1970-01-01
      • 1970-01-01
      • 2010-12-16
      相关资源
      最近更新 更多