【问题标题】:Use variable as form fields in Django form template在 Django 表单模板中使用变量作为表单字段
【发布时间】:2022-01-05 00:59:36
【问题描述】:
<here all loading of static , template_filters, crispy_forms >

<form>
{% for i in artifact_length %}
   {% with artifact_name="artifact"|artifact_name:forloop.counter0 %}
        {{form.artifact_name|as_crispy_field}}
   {% endwith %}
{%endfor%}
</form>

这是相关的模板代码。在这里,我想将名称为 artifact_0artifact_1 的表单字段呈现为来自表单。 with 内的变量 artifact_name 工作正常并返回预期的标识符 artifact_0artifact_1,但我想将这些变量用作表单字段以呈现为 as_crispy_field。 代码{{form.artifact_name|as_crispy_field}} 不打印任何内容,因为它假定表单为名称为artifact_name 的字段,但事实并非如此。相反,我想在这里使用变量的值。

forms.py

  class Someform(forms.form):
    def __init__(self, artifact_obj):
        super().__init__()
        count = 0
        for artifact in artifact_obj:
            self.fields[f'artifact_{count}'] = forms.CharField(widget=forms.NumberInput())
                count += 1
tags.py

@register.filter('artifact_name')
def get_artifact_name(artifact_prefix: str, counter: int):
    print('method', 'prefix', artifact_prefix, 'counter', counter)
    return f'{artifact_prefix}_{counter}'

正在创建可变长度表单。如 informs.py 表单字段是使用 artifact_count 创建的,其中 count 的范围可以从 0 到 obj 的 len。

【问题讨论】:

  • 这些是您表单中唯一的字段吗?len(artifact_obj) 是否与 artifact_length 相同?
  • 还有更多字段,我可以按名称对它们进行排序。但这些都是可变字段,无法估计会有多少。需要循环迭代。 .是的,artifact_length 与 artifact_obj 相同。
  • 它在上下文中被传递为{'artifact_length':range(len(artifact_obj))}
  • 其他字段的渲染顺序如何?
  • 顺序无关紧要,我只是将它们呈现在所有这些变量字段之上。现在也需要渲染这些字段

标签: django django-views django-forms django-templates django-template-filters


【解决方案1】:

您不需要为此目的使用过滤器/模板标签等。最简单的解决方案是 loop over the form fields 来渲染它们:

<form>
{% for field in form %}
    {{ field|as_crispy_field }}
{%endfor%}
</form>

这将遍历表单中的所有字段。

如果您特别关心这些字段的顺序,可以调用表单order_fields method

class Someform(forms.form):
    def __init__(self, artifact_obj, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for count, artifact in enumerate(artifact_obj):
            self.fields[f'artifact_{count}'] = forms.CharField(widget=forms.NumberInput())
        self.order_fields(["field_1", "field_2", ...] + [f"artifact_{i}" for i, _ in enumerate(artifact_obj)] + [..., "field_n"])

如果您特别想单独呈现其他字段,您可以在表单中添加一个方法,让您可以遍历这些字段:

class Someform(forms.form):
    def __init__(self, artifact_obj, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for count, artifact in enumerate(artifact_obj):
            self.fields[f'artifact_{count}'] = forms.CharField(widget=forms.NumberInput())
        self.artifact_length = len(artifact_obj)
    
    def artifact_fields(self):
        return [self[f'artifact_{i}'] for i in range(self.artifact_length)]

然后在模板中循环这些:

<form>
{% for field in form.artifact_fields %}
    {{ field|as_crispy_field }}
{%endfor%}
</form>

【讨论】:

  • 非常感谢。有用。我通过使用模板标签、过滤器找到了一种解决方法,但是太冗长了。有额外的方法来打印工件是个好主意。
  • 现在有一个错误。当我提交表单并执行此if request.method == 'POST': form = Someform(request.POST) if form.is_valid(): 它现在抛出错误,我可以理解为构造函数采用artifact_obj 并得到request.POST。如何解决这个问题?我需要args and **kwargs?
  • @JohnByro 看到我的编辑,是的,你应该使用*args, **kwargs。此外,无论请求方法如何,您都应该通过artifact_obj,所以Someform(artifact_obj, request.POST)
  • 你能建议我们如何动态删除这些字段,因为我们在上面的帖子中添加了它们。
猜你喜欢
  • 2018-06-05
  • 2011-06-26
  • 2012-03-02
  • 1970-01-01
  • 2013-07-17
  • 2011-10-11
  • 1970-01-01
  • 1970-01-01
  • 2018-01-28
相关资源
最近更新 更多