Django 渲染未验证数据的表单

0 投票
1 回答
1744 浏览
提问于 2025-04-17 19:04

我写了这个联系表单,参考了一些Django的文档:

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            name = form.cleaned_data['name']
            subject = form.cleaned_data['subject']
            message = form.cleaned_data['message']
            sender = form.cleaned_data['sender']
            cc_myself = form.cleaned_data['cc_myself']

            recipients = ['name@e-mail.com']
            if cc_myself:
                recipients.append(sender)

            m = '%s\n\n-----------------\n%s' % (message, name)
            from django.core.mail import send_mail
            send_mail(subject, m, sender, recipients)
            return HttpResponseRedirect('/kontakt/tack/')
    else:
        form = ContactForm()

    return render(request, 'contact/index.html', {
        'form': form,
    })

问题是,如果表单没有通过验证,它会返回一个空的表单。这对那些写了很长信息但忘记填写名字的人来说,可能会很烦人。

我通过把下面的代码中最后的 else: 改成这样来解决这个问题:

    try:
        form = ContactForm(form.cleaned_data)
    except UnboundLocalError:
        form = ContactForm()

我需要在页面第一次渲染时使用 try 语句,因为那时候还没有 form.cleaned_data。这样做是有效的,但看起来像是个比较丑陋的解决办法。

有没有什么标准的方法可以在重新渲染表单时使用之前填写的文本,而不需要我这种丑陋的 try-except 解决方案呢?

请求的模板

{% block content %}
      <div id="contact-generic-container">
        <p>Lorem ipsum (not really, but ain't relevant).</p>
      </div> <!-- #contact-generic-container -->
      <div id="contact-form" class="clearfix">
    <br/>
    <h2>Kontakta oss!</h2>
    <form action="/kontakt/" method="post">
      {{ form.non_field_errors }}
      <fieldset class="text">
        {% csrf_token %}
            <div class="field-wrapper">
          <label for="id_name">Namn:</label>
        {{ form.name }}
                {{ form.name.errors }}
        </div>
            <div class="field-wrapper">
          <label for="id_sender">E-post:</label> 
        {{ form.sender }}
                {{ form.sender.errors }}
        </div>
            <div class="field-wrapper">
          <label for="id_subject">Ämne:</label> 
        {{ form.subject }}
                {{ form.subject.errors }}
        </div>
      </fieldset>
      <fieldset class="text">
          <div class="field-wrapper">
        <label for="id_message">Meddelande:</label><br/>
        {{ form.message }}
            {{ form.message.errors }}
      </div>
          <div class="field-wrapper">
        <label for="id_cc_myself">Kopia till mig själv:</label> 
        {{ form.cc_myself }}
            {{ form.cc_myself.errors }}
      </div>
      <input type="submit" value="Skicka" />
      <fieldset class="text">
    </form>
      </div>
{% endblock %}

1 个回答

2

这里有个简单的方法,可以让表单总是用POST数据初始化,或者什么都不初始化:

def contact(request):
    form = ContactForm(request.POST or None)
    if request.POST and form.is_valid():

然后去掉你的else部分。

这样表单里总会有数据,即使是GET请求也不会报错。

因为我用了点Python的小技巧,接下来我来解释一下。

  1. Python支持在表达式中使用和/或运算符。
  2. 当计算or时,Python会在第一个返回“真”的值时停止。
  3. 当计算and时,如果第一个条件返回“假”,Python会停止。

所以,当我们初始化表单时,我们让Python去赋值,要么是request.POST的值(如果它是真的),要么是None(如果request.POST是假的,也就是空的)。这样在有POST请求时,表单就会正确地用request.POST里的值初始化,而在没有POST请求时则是None。

在我们的if语句中,如果request.POST是假的(也就是空的),Python就会在这里停止,不会调用form.is_valid(),所以我们就不用担心在没有POST请求的情况下进行验证。

是不是很酷呢?

撰写回答