【问题标题】:Django form changing required field depending on another fieldDjango表单根据另一个字段更改必填字段
【发布时间】:2021-05-11 10:58:09
【问题描述】:

我有一个 django 表单 InstellingenForm,它有几个输入字段。都应该是必需的。但是根据“spelmodus”的输入,“tijd”或“wooden”应该变成 required=False。 (如果在“spelmodus”中选择了“tijd”,则“wooden”形式应更改为 required=False,反之亦然)我尝试使用 clean() 函数执行此操作,但我似乎无法弄清楚如何正是这样做。

forms.py:

from django import forms

SPELMODUS = [
    ("", ""),
    ('tijd', 'Tijd'),
    ('woorden', 'Woorden'),
]

TIJD = [
    ("", ""),
    ('een', '1 minuut'),
    ('twee', '2 minuten'),
    ('vijf', '5 minuten'),
]

WOORDEN = [
    ("", ""),
    ('vijftig', '50 woorden'),
    ('honderd', '100 woorden'),
    ('honderdvijftig', '150 woorden'),
]

TALEN = [
    ("", ""),
    ('nederlands', 'Nederlands'),
    ('engels', 'Engels'),
]

MOEILIJKHEID = [
    ("", ""),
    ('makkelijk', 'Makkelijk'),
    ('gemiddeld', 'Gemiddeld'),
    ('moeilijk', 'Moeilijk'),
]


class InstellingenForm(forms.Form):
    naam = forms.CharField(label="Naam", max_length=10, required=True, widget=forms.TextInput(attrs={'class': 'input-container'}))
    spelmodus = forms.ChoiceField(label="Spelmodus", choices=SPELMODUS, required=True, widget=forms.Select(attrs={'class': 'input-container', 'id': 'spelmodus', 'onchange': 'hideShow(this.value)', }))
    tijd = forms.ChoiceField(label="", choices=TIJD, widget=forms.Select(attrs={'class': 'input-container', 'id': 'tijdClass'}))
    woorden = forms.ChoiceField(label="", choices=WOORDEN, widget=forms.Select(attrs={'class': 'input-container', 'id': 'woordenClass'}))
    taal = forms.ChoiceField(label="Taal", choices=TALEN, required=True, widget=forms.Select(attrs={'class': 'input-container'}))
    moeilijkheid = forms.ChoiceField(label="Moeilijkheid", choices=MOEILIJKHEID, required=True, widget=forms.Select(attrs={'class': 'input-container'}))

    def clean(self):
        if self.data.get('spelmodus', 'tijd'):
            self.fields['woorden'].required = False
        elif self.data.get('spelmodus', 'woorden'):
            self.fields['tijd'].required = False
        super(InstellingenForm, self)._clean_fields()

views.py:

def instellingenDatabase(request):
    if request.method == "POST":
        form = InstellingenForm(request.POST)
        if form.is_valid():
            return HttpResponseRedirect('/')
    rendered = render(request, 'instellingenDatabase.html', {
        'formulier': form
    })
    return HttpResponse(rendered)

instellingenDatabase.html:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    {% load static %}
    <link rel="stylesheet" type="text/css" href="{% static 'instellingen.css' %}">
    <script type='text/javascript' src="{% static 'instellingen.js' %}"></script>
</head>

<body>
    {% include "header.html" %}
    <div class="bodypage">
        <div class="settings-container">
            <div class="playText">
                Play
            </div>
            <form method="post">
                {% csrf_token %}
                <table>
                {% for field in formulier %}
                    {{ field.label }}
                    {{ field }}
                {% endfor %}
                </table>
                <br>
                <button type="submit" name="Start" value="Start" class="button">Start</button>
            </form>
        </div>
    </div>

</body>

</html>

【问题讨论】:

  • 除了将它传递给上下文之外,您甚至不使用视图中的表单吗?你期望会发生什么?最多你会被重定向到 url /...
  • 我重定向到 url / 只是为了检查表单验证是否有效。如果按下开始,它应该重定向到 /
  • 您甚至没有检查表单是否有效,您如何期望重定向显示“表单验证有效”?一个人使用is_valid method of the form(在您的情况下为form = InstellingenForm(request.POST)在绑定表单上,以防提交表单,即请求是发布请求)来检查它是否有效。你还没有在任何地方使用过。
  • 我已经用 is_valid() 编辑了 views.py,但我觉得我没有正确地做,因为 'formulier': form 没有得到 InstellingenForm
  • 我已经编辑了我的答案,请检查一下。

标签: python django django-forms


【解决方案1】:

您的方法不起作用,因为在调用 clean 之前,这些字段已经被清理了。您应该覆盖__init__,而不是针对您可能想要对表单进行的这些类型的更改。:

class InstellingenForm(forms.Form):
    naam = forms.CharField(label="Naam", max_length=10, required=True, widget=forms.TextInput(attrs={'class': 'input-container'}))
    spelmodus = forms.ChoiceField(label="Spelmodus", choices=SPELMODUS, required=True, widget=forms.Select(attrs={'class': 'input-container', 'id': 'spelmodus', 'onchange': 'hideShow(this.value)', }))
    tijd = forms.ChoiceField(label="", choices=TIJD, widget=forms.Select(attrs={'class': 'input-container', 'id': 'tijdClass'}))
    woorden = forms.ChoiceField(label="", choices=WOORDEN, widget=forms.Select(attrs={'class': 'input-container', 'id': 'woordenClass'}))
    taal = forms.ChoiceField(label="Taal", choices=TALEN, required=True, widget=forms.Select(attrs={'class': 'input-container'}))
    moeilijkheid = forms.ChoiceField(label="Moeilijkheid", choices=MOEILIJKHEID, required=True, widget=forms.Select(attrs={'class': 'input-container'}))

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if 'spelmodus' in self.data:
            spelmodus = self.data.get('spelmodus')
            if spelmodus == 'tijd':
                self.fields['woorden'].required = False
            elif spelmodus == 'woorden':
                self.fields['tijd'].required = False

此外,您从未在视图中使用过该表单。您只需将它传递给上下文并渲染它。如果要检查表单是否有效,则需要使用is_valid 方法。您已在编辑中添加了该内容,但现在您从未在 GET 请求的情况下制作表单,您也需要这样做:

def instellingenDatabase(request):
    if request.method == "POST":
        form = InstellingenForm(request.POST)
        if form.is_valid():
            print(form.cleaned_data.get('spelmodus')) # Check value of spelmodus
            return HttpResponseRedirect('/')
        print(form.errors) # print errors here in case form is invalid
    else:
        form = InstellingenForm() # instantiate form in case of GET request
    rendered = render(request, 'instellingenDatabase.html', {
        'formulier': form
    })
    return HttpResponse(rendered)

此外,当您手动呈现表单时,最好也呈现错误,这样用户就可以知道出了什么问题:

{% for field in formulier %}
    {{ field.label }}
    {{ field }}
    {{ field.errors }}
{% endfor %}
{{ formulier.non_field_errors }}

【讨论】:

  • 看来 woorden 和 tijd 仍然在 required=True 上,因为如果我尝试使用它,它对我不起作用
  • @C.vanVeen 你在表格中为spelmodus 指定了什么值?
  • 如果您指的是 SPELMODUS 选项中的值,我认为是 tijd 或 Tijd,但我对此不太熟悉。
  • @C.vanVeen 如果您在提交表单时选择了Tijd,那么woorden 将具有required = False。你说这行不通?表单显示的错误是什么?或者print(form.errors) 给你什么输出? (写在某处,以便在form.is_valid()返回false时运行)
  • 打印语句放在哪里?
猜你喜欢
  • 2015-07-19
  • 1970-01-01
  • 1970-01-01
  • 2018-02-16
  • 1970-01-01
  • 2015-07-15
  • 2016-07-20
  • 1970-01-01
  • 2013-01-04
相关资源
最近更新 更多