WEB后端服务第23天-Django项目第3天
一、form表单类
form表单类主要用于渲染前端form表单的,也可以用于site站点的form表单页面。
1.1 创建form表单类
通过在app模块下创建forms.py脚本,内容如下:
from django import forms
from .models import AppUser
class AppUserForm(forms.ModelForm):
name = forms.CharField(min_length=8,
max_length=20,
required=True,
error_messages={
'required': '账户不能为空',
'max_length': '账户不能超过20个字符',
'min_length': '账户不能少于8个字符'
})
auth_key = forms.CharField(widget=forms.PasswordInput(render_value=True),
label='口令',
min_length=6,
error_messages={
'required': '口令不能为空',
'min_length': ' 口令不少于6位'
})
phone = forms.CharField(max_length=11,
min_length=11,
required=False, label='手机号')
class Meta:
model = AppUser # 指定模型类
fields = ('id', 'img1', 'name', 'auth_key', 'phone', 'email')
error_messages = {
'email': {
'required': '邮箱不能为空'
}
}
在表单类中,可以声明表单字段, 字段的类型与Model模型的字段类型要一一匹配,除此之外,表单注重地的验证规则和渲染数据。
在Meta类中,error_messages是指定Model模型类的字段验证错误的提示信息。而在forms.xxxField()的erorr_messages是指定当前字段的不同验证规则 的错误信息,如required表示必填项, min_length表示最小值, max_length表示最大值。
1.2 使用form表单类
在admin.py脚本中,应用表单类
from .forms import AppUserForm
class AppUserAdmin(admin.ModelAdmin):
list_display = ('name', 'phone', 'email', 'create_time', 'status')
form = AppUserForm
admin.site.register(AppUser, AppUserAdmin)
1.3 自定义验证规则
通过forms的字段类可以做一些通常验证,但复杂的验证规则,需要重写clean_xxx()函数,在AppUserForm中增加验证口令的方法。规则是必须包含大写、小写和数字:
def clean_auth_key(self):
# 以上验证都通过了
# 自定义验证规则: 必须包含大写、小写和数字等字符
auth_key = self.cleaned_data.get('auth_key')
if all((
re.search(r'\d+', auth_key),
re.search(r'[a-z]+', auth_key),
re.search(r'[A-Z]+', auth_key)
)):
print('-----clean_auth_key-----')
return auth_key
raise ValidationError('口令必须包含大写、小写和数字等字符')
如果验证没有通过,form表单要收集错误信息,必须通过raise ValidationError(message)抛出异常。
二、自定义小部件widget
2.1 源码分析
django.forms.widgets.TextInput源码
class TextInput(Input):
input_type = 'text'
template_name = 'django/forms/widgets/text.html'
class Input(Widget):
"""
Base class for all <input> widgets.
"""
input_type = None # Subclasses must define this.
template_name = 'django/forms/widgets/input.html'
def __init__(self, attrs=None):
if attrs is not None:
attrs = attrs.copy()
self.input_type = attrs.pop('type', self.input_type)
super().__init__(attrs)
def get_context(self, name, value, attrs):
context = super().get_context(name, value, attrs)
context['widget']['type'] = self.input_type
return context
init()函数是在表单字段中指定的参数
get_context()是在渲染模板时,返回的上下文数据
2.2 创建资源
在app模块下创建widgets.py脚本和templates模板目录,widgets.py脚本的内容如下:
# 自动生成ID的输入框
class IDWidget(TextInput):
def get_context(self, name, value, attrs):
# 新增用户时
if not value:
value = uuid.uuid4().hex
return super().get_context(name, value, attrs)
# 发送邮件的按钮
class SendEmailWidget(TextInput):
template_name = 'send_email_widget.html'
# render_value 是否渲染现有的值
def __init__(self, attrs=None, render_value=True):
super().__init__(attrs)
self.render_value = render_value
def get_context(self, name, value, attrs):
if not self.render_value:
value = None
return super().get_context(name, value, attrs)
在templates目录下,创建mail_widget.html文件,内容如下:
<input type="{{ widget.type }}" name="{{ widget.name }}"{% if widget.value != None %} value="{{ widget.value|stringformat:'s' }}"{% endif %} />
</div>
<div style="padding: 5px" >
<button type="button"
style="padding: 5px 10px;
border-radius: 5px;
background-color:lightblue;"
onclick="send('{{ widget.value }}')">发送激活邮件</button>
<script>
function send(email) {
fetch('/send_mail/'+email+"/")
.then(resp=>resp.json())
.then(data=>{
alert(data.msg);
})
}
</script>
2.3 在forms表单中应用
在forms.py的脚本中
class AppUserForm(forms.ModelForm):
id = forms.CharField(widget=IDWidget,
min_length=32, max_length=32,
label='主键', disabled=True)
# 通过widget属性指定自定义widget部件
email = forms.CharField(required=False,
widget=SendEmailButton,
label='邮箱')
三、django中邮件发送
3.1 选择邮箱
在此配置了163的邮箱, 从设置页面中获取到smtp的服务器相关信息
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 25
EMAIL_HOST_USER = 'disenQF@163.com'
EMAIL_HOST_PASSWORD = 'xapython1903'
EMAIL_HOST_PASSWORD 使用了授权码。
3.2 django.core.mail.send_mail()
from django.core.mail import send_mail as send_163_email
def send_mail(request, email):
print('send_mail', email)
subtitle = '用户激活通知'
message = '<html>亲爱的, 注册的用户disen!请先<a href="/">激活的用户</a></html>'
send_163_email(subtitle, '', html_message=message,
from_email='disenQF@163.com',
recipient_list=[email])
return JsonResponse({
'msg': '发送成功',
'info': {
'email': email
}
})
3.3 Python原生发送邮件
import smtplib
from email.mime.text import MIMEText
from email.header import Header
def send_message(title, message, receivers):
client = smtplib.SMTP('smtp.163.com',port=25)
client.debuglevel = 1
client.login('disenQF@163.com', 'xapython1903')
# message = '<html><h3>亲爱的Disen:</h3><p>您注册的用户需要<a href="http://localhost:8080/">激活</a>才能正常使用</p></html>'
# title = '易果平台-用户激活通知'
# 第二个参数是内容的类型, html 富文本, plain 文本
message = MIMEText(message, 'html', 'utf-8')
message['Subject'] = Header(title, 'utf-8')
message['From'] = 'disenQF@163.com'
message['To'] = ','.join(receivers)
client.send_message(message,
from_addr='disenQF@163.com',
to_addrs=receivers)
print('---ok--')
【注意】: 554错误, 经常是MIMEText的发送者和接收者的信息与send_message()中的发送者和接收者不匹配。解决的办法:改成一致的。