Django Forms.py电子邮件和电话验证

4
我有一个使用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来实现这一点?

可能重复:https://dev59.com/N7bna4cB1Zd3GeqPaWmE - Brian Dant
2个回答

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/和phonenumbers文档。例如:

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链接吗?这就是我遇到的问题。 - meknajirta

0
一个第三方包(这里)将包含您所需的电话号码验证。
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)
    ...

请注意项目 README 中的注释:

可以通过 django 设置模块中的 PHONENUMBER_DB_FORMAT 变量设置表示形式。此变量必须是“E164”、“INTERNATIONAL”、“NATIONAL”或“RFC3966”之一。推荐使用全球通用格式“E164”、“INTERNATIONAL”或“RFC3966”。'NATIONAL' 格式需要设置 PHONENUMBER_DEFAULT_REGION 变量。

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

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


很有趣,我们又回到了你最初的问题:如何实现 django-phonenumbers 包? :) - Brian Dant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接