BBS之注册功能
前端
模板层
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录</title>
{% load static %}
<link rel="stylesheet" href="{% get_static_prefix %}bootstrap-3.3.7-dist/css/bootstrap.css">
<script src="{% get_static_prefix %}jquery-3.3.1.js"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-4 col-md-offset-4 bg-success clearfix img-rounded" style="padding-bottom: 30px">
<h1 style="text-align: center">注册</h1>
<form id="reg_form" novalidate>
{% csrf_token %}
{% for foo in my_form %}
<div class="form-group">
<label for="{{ foo.auto_id }}">{{ foo.label }}</label><span style="color: red;" id="error"
class="pull-right"></span>
{{ foo }}
</div>
{% endfor %}
<div class="form-group">
<label for="my_file">头像
<img src="/static/image/default.png" alt="" id="picture" width="80" height="80">
</label>
<input type="file" class="hidden" id="my_file" required>
</div>
</form>
<span style="margin-left: 230px;color: red" id="msg"></span>
<button type="button" class="btn btn-info btn-lg pull-right active " id="btn">注册</button>
</div>
</div>
</div>
</body>
<script>
$('#my_file').change(function () {
// 先获得图片$('#my_file')[0].files[0],生成图片对象file
var file = $(this)[0].files[0];
// 生成一个文件阅读器
var read = new FileReader();
// 文件阅读器读入图片
read.readAsDataURL(file);
// 由于图片是属于页面资源,必须等页面加载完才显示图片
read.onload = function () {
$('#picture').attr('src', read.result)
}
})
$('#btn').click(function () {
var formdata = new FormData();
// 调用表单的serializeArray()方法序列化表单元素,以列表套字典[{name: "username", value: ""},.....]
var arrt = $('#reg_form').serializeArray();
// $.each(被循环的,循环体(匿名函数)):JQ的循环方法
$.each(arrt, function (index, data) {
formdata.append(data.name, data.value)
})
// 单独添加文件
formdata.append('my_file', $('#my_file')[0].files[0]);
$.ajax({
url: '/register/',
type: 'post',
processData: false,
contentType: false,
data: formdata,
success: function (data) {
if (data.status == '200') {
$('#msg').text('注册成功')
}
else if (data.status == '404') {
$('#msg').text('头像上传失败')
}
else if (data.status == '401') {
// data.error得到的是错误信息,字典套列表{'username':[错误信息]..},循环得到key值
for (let i in data.error) {
// 循环判断错误的是那些
$.each(arrt, function (index, value) {
if (i == value.name) {
// 把input的前一个同辈标签span的text变成错误信息data.error[i][0]
$('#id_' + i).prev('span').text(data.error[i][0])
}
})
}
// 如果有全局错误信息,显示到$('#msg').text(data.error['__all__'])
if (data.error['__all__']) {
$('#msg').text(data.error['__all__'])
}
}
}
})
})
</script>
</html>
后端
from django import forms
from django.forms import widgets
from blog.models import UserInfo
from django.core.exceptions import ValidationError
class User_from(forms.Form):
username = forms.CharField(label='用户名', max_length=10, min_length=3,widget=widgets.TextInput(attrs={'class': 'form-control'}),error_messages={'max_length': '最长是19', 'min_length': '最短是3', 'required': '不能为空'}, )
password = forms.CharField(label='密码', max_length=10, min_length=3,widget=widgets.PasswordInput(attrs={'class': 'form-control'}),error_messages={'max_length': '最长是0', 'min_length': '最短是3', 'required': '不能为空'})
re_password = forms.CharField(label='确认密码', max_length=10, min_length=3,widget=widgets.PasswordInput(attrs={'class': 'form-control'}),error_messages={'max_length': '最长是10', 'min_length': '最短是3', 'required': '不能为空'})
email = forms.EmailField(label='邮箱', error_messages={'required': '不能为空','invalid': '不符合邮箱格式'},widget=widgets.EmailInput(attrs={'class': 'form-control'}))
def clean_username(self):
name = self.cleaned_data.get('username')
name_db = UserInfo.objects.filter(username=name).first()
if name_db:
raise ValidationError('用户已存在')
return name
def clean(self):
pwd = self.cleaned_data.get('password')
re_pwd = self.cleaned_data.get('re_password')
if pwd and re_pwd:
if pwd != re_pwd:
raise ValidationError('两次密码不一致')
return self.cleaned_data
视图层
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from blog import myform
from blog.models import UserInfo
def register(requset):
response = {'status': 200, 'error': None}
if requset.method == 'POST':
# 将所有POST数据放入放入form组件验证
my_form = myform.User_from(requset.POST)
# 验证通过
if my_form.is_valid():
# 将验证通过的数据放到dic里
dic = my_form.cleaned_data
# 去除不需要存入数据库的re_password
dic.pop('re_password')
# 获得文件
my_file = requset.FILES.get('my_file')
# 为了区分头像,加上前缀
my_file.name = requset.POST.get('username') + '_' + my_file.name
if my_file:
# 在dic中添加头像数据
dic['avatar'] = my_file
# 创建用户
UserInfo.objects.create_user(**dic)
else:
response['status'] = 404
else:
response['status'] = 401
response['error'] = my_form.errors
return JsonResponse(response)
my_form = myform.User_from()
return render(requset, 'register.html', locals())
总结
基于forms组件和Ajax实现注册功能
# 1 基于forms组件设计注册页面
---点击头像===点击input
---头像预览:
1 获取用户选中的文件对象
2 获取文件对象的路径
3 修改img的src属性 ,src=文件对象的路径
# 2 错误信息:
// data.error得到的是错误信息,字典套列表{'username':[错误信息]..},循环得到key值
for (let i in data.error) {
// 循环判断错误的是那些
$.each(arrt, function (index, value) {
if (i == value.name) {
// 把input的前一个同辈标签span的text变成错误信息data.error[i][0]
$('#id_' + i).prev('span').text(data.error[i][0])
}
})
}
// 如果有全局错误信息,显示$('#msg').text(data.error['__all__'])
if (data.error['__all__']) {
$('#msg').text(data.error['__all__'])
}
# 3 局部钩子和全局钩子校验
user字段不能重复
两次密码不一致
# 4 FileField与ImageFiled
区别是:
fileField是可以任何文件
ImageFile只能是图片文件
class UserInfo(AbstractUser):
nid = models.AutoField(primary_key=True)
# 电话可以为空
phone = models.CharField(max_length=32, null=True)
# 头像
avatar = models.FileField(upload_to='static/avatar/', default='/static/image/default.png')
# 站点
blog = models.OneToOneField(to='Blog', to_field='nid',null=True)
Dajngo实现:
会将文件对象下载到项目中avatars文件夹中(如果没有avatar文件夹,Django会自动创建)