【问题标题】:Django Forms.py Email And Phone ValidationDjango Forms.py 电子邮件和电话验证
【发布时间】:2020-04-05 07:39:31
【问题描述】:

我有一个使用 forms.py 创建的联系表单,我想使用正则表达式或任何内置的 Django 验证器为电子邮件和电话字段添加验证。我使用的唯一文件是 forms.py、views.py 和 html 模板(此联系表单没有 models.py)。如果用户输入了错误的电话号码或电子邮件,我想向他们显示一条消息,说明他们的格式不正确并且他们需要更正输入。在用户输入有效数据之前,该表单应该无法提交。

现在在表单中输入虚假数据然后提交它会导致表单不执行任何操作(它转到 url 中的 #)但用户不知道电子邮件是否发送。

我在下面尝试了什么:

Forms.py:

from django import forms
from django.core.validators import EmailValidator
from django.core.exceptions import ValidationError
from django.core.validators import validate_email
​
class ContactForm(forms.Form):
    contact_name = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control', 'autocomplete':'off'}), required=True)
    contact_email = forms.EmailField(error_messages={'invalid': 'This is my email error msg.'}, widget=forms.TextInput(attrs={'class':'form-control', 'autocomplete':'off'}), required=True)
    contact_subject = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control', 'autocomplete':'off'}), required=True)
    contact_phone = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control', 'autocomplete':'off'}), required=True)
    content = forms.CharField(
    required=True,
    widget=forms.Textarea(attrs={'class':'form-control', 'autocomplete':'off'})
    )
​
    # the new bit we're adding
    def __init__(self, *args, **kwargs):
        super(ContactForm, self).__init__(*args, **kwargs)
        self.fields['contact_name'].label = "Full Name:"
        self.fields['contact_email'].label = "Email:"
        self.fields['contact_subject'].label = "Subject:"
        self.fields['contact_phone'].label = "Phone:"
        self.fields['content'].label = "Message:"
​
    def clean_email(self):
        email = self.cleaned_data['contact_email']
        validator = RegexValidator("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
        validator(email)
        return email

Views.py:

def contact(request):
    form_class = ContactForm
​
    # new logic!
    if request.method == 'POST':
        form = form_class(data=request.POST)
​
        if form.is_valid():
​
            recaptcha_response = request.POST.get('g-recaptcha-response')
            url = 'https://www.google.com/recaptcha/api/siteverify'
            payload = {
                'secret': settings.GOOGLE_RECAPTCHA_SECRET_KEY,
                'response': recaptcha_response
            }
            data = urllib.parse.urlencode(payload).encode()
            req = urllib.request.Request(url, data=data)

            response = urllib.request.urlopen(req)
            result = json.loads(response.read().decode())

            print('result:' + str(result))
​
            print('recaptcha_response:' + str(recaptcha_response))
​
            print('result_success:' + str(result['success']))

​
​
            if (not result['success']) or (not result['action'] == 'contact'):
                messages.error(request, 'Invalid reCAPTCHA. Please try again.')
​
            contact_name = request.POST.get(
                'contact_name'
            , '')
            contact_subject = request.POST.get(
                'contact_subject'
            , '')
            contact_email = request.POST.get(
                'contact_email'
            , '')
            contact_phone = request.POST.get(
                'contact_phone'
            , '')
            form_content = request.POST.get('content', '')
​
            # Email the profile with the
            # contact information
            template = get_template('contact_template.txt')
            context = {
                'contact_name': contact_name,
                'contact_email': contact_email,
                'contact_subject': contact_subject,
                'contact_phone': contact_phone,
                'form_content': form_content,
            }
            content = template.render(context)
​
            email = EmailMessage(
                contact_subject,
                content,
                "Your website" +'',
                ['email@gmail.com'],
                headers = {'Reply-To': contact_email }
            )
            email.send()
            messages.info(request, "Your message was sent successfully. Thank you for reaching out.")
​
    return render(request, 'contact.html', {
        'form': form_class,
    })

HTML模板:

<form id='cform' action="#" method="post">
    {% csrf_token %}
    {{ form.as_p }}

    <script src='https://www.google.com/recaptcha/api.js?render=<KEY>'></script>
    <div class="g-recaptcha" data-sitekey="<KEY>"></div>
    <script>
        grecaptcha.ready(function() {
            grecaptcha.execute('<KEY>', {action: 'contact'})
            .then(function(token) {
                ginput = document.createElement('input');
                ginput.type = "hidden";
                ginput.name = "g-recaptcha-response";
                ginput.value = token;
                document.getElementById("cform").appendChild(ginput);
            });
        });
    </script>
    <button type="submit" class="btn btn-primary form-control">Submit</button>
</form>

我将如何仅使用 Django 而不使用 JavaScript 来做到这一点?

【问题讨论】:

标签: python django validation contact-form


【解决方案1】:

您可以使用EmailValidator 代替RegexValidator。这样您就不需要编写可以可靠地测试电子邮件地址的正则表达式(这很难做到正确)。

为了验证电话号码,我会使用 phonenumbers 库。 https://github.com/daviddrysdale/python-phonenumbers

更新

Djano 表单文档非常好。答案在这里https://docs.djangoproject.com/en/3.0/ref/forms/

我会给你一些建议。

使用基于类的视图处理表单的示例是联系表单。

https://docs.djangoproject.com/en/3.0/topics/class-based-views/generic-editing/

这个参考非常好:

https://ccbv.co.uk/projects/Django/2.2/django.views.generic.edit/FormView/

对于电子邮件字段,您尝试执行的所有操作均由默认值处理。这就够了:

class ContactForm(forms.Form):
    contact_email = forms.EmailField()

对于电话号码,您可以编写自己的验证器,参考https://docs.djangoproject.com/en/3.0/ref/forms/validation/ 和电话号码文档。比如:

from django.core.exceptions import ValidationError
import phonenumbers

def validate_phone_number(value):
    z = phonenumbers.parse(value, None)
    if not phonenumbers.is_valid_number(z):
        raise ValidationError(
            _('%(value) is not a valid phone number'),
            params={'value': value},
        )

然后

contact_phone = models.CharField(validators=[validate_phone_number])

【讨论】:

  • 你能告诉我如何在我的代码中实现 EmailValidator 和电话号码 github 链接吗?这就是我遇到的麻烦。
【解决方案2】:

第三方包 (here) 将包含您寻求的电话号码验证。

pip install django-phonenumber-field
pip install phonenumbers
# forms.py
...
from phonenumber_field.formfields import PhoneNumberField
...

class ContactForm(forms.Form):
    ... 
    contact_email = forms.EmailField(
        error_messages={'invalid': 'This is my email error msg.'}, 
        widget=forms.TextInput(attrs={'class':'form-control', 'autocomplete':'off'}), 
        required=True)
    ...
    contact_phone = PhoneNumberField(required=True)
    ...

还要注意项目自述文件中的注释:

表示可以通过 django 中的 PHONENUMBER_DB_FORMAT 变量设置 设置模块。此变量必须是“E164”、“INTERNATIONAL”、 “国家”或“RFC3966”。推荐是具有全球意义的之一 格式为“E164”、“INTERNATIONAL”或“RFC3966”。 “国家”格式 需要设置 PHONENUMBER_DEFAULT_REGION 变量。

返回的对象是 PhoneNumber 实例,而不是字符串。如果 字符串用于初始化它,例如通过 MyModel(phone_number='+41524204242') 或表单处理,它必须是 带有国家代码的电话号码。

因此,您可以(大概我没有测试过)通过这些设置配置表单小部件,以根据您的特定标准验证电话号码。 (请参阅底层包中的配置选项,phonenumbers

【讨论】:

  • @meknajirta:有趣的是,我们回到了您最初的问题:我如何实现django-phonenumbers 包? :)
猜你喜欢
  • 1970-01-01
  • 2013-11-07
  • 2015-03-15
  • 2018-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多