一.在urls中写路由
二.返回登录页面(login.html中写前端代码)
- username(用户名)
- password(密码)
- validCode(验证码)
-submit(提交按钮)
-submit
-前端:显示的验证码图片
<div class="col-md-6">
<img class="validCode_img" src="/get_validCode_img/" alt="" width="200px" height="50px">
</div>
-后端:
方式一:以二进制打开一个图片路径,获取内容 返回给前端
import os
path=os.path.join(settings.BASE_DIR,"blog","static","img","egon.jpg")
with open(path,"rb",)as f:
data = f.read()
方式二:导入Image,还是以二进制打开一个图片路径,获取内容,返回给前端
from PIL import Image
img=Image.new(mode="RGB",size=(120,40),color="blue")
f = open("validCode.png","wb")
img.save(f,"png")
with open("validCode.png","rb") as f:
data = f.read()
方式三:
from io import BytesIO //导入文件句柄的对象和Image
from PIL import Image
img = Image.new(mode="RGB",size=(120,40),color="yellow") //创建一个img图片的对象
f=BytesIO() //创建一个内存句柄的对象
img.save(f,"png")
data = f.getvalue()
方式四: //创建一个img对象,获取一个画笔,创建字体font。定义一个列表,用for循环随机取出数字或者字母
from io import BytesIO
import random
from PIL import Image,ImageDraw,ImageFont
img = Image.new(mode="RGB",size=(120,40),color=(random.randint(0,255),random.randint(0,255),random.randint(0,255)))
draw = ImageDraw.Draw(img,"RGB") #获取一个画笔
font = ImageFont.truetype("blog/static/font/kumo.ttf",28)
valid_list = []
for i in range(4):
random_num = str(random.randint(0,9))
random_lower_zimu = chr(random.randint(65,90))
random_upper_zimu = chr(random.randint(97,122))
random_char = random.choice([random_num,random_lower_zimu,random_upper_zimu])
draw.text([4+i*24,10],random_char,(random.randint(0,255),random.randint(0,255),random.randint(0,255)),font=font)
valid_list.append(random_char)
f=BytesIO() //拿到一个句柄对象
img.save(f,"png") //用什么格式保存该图片
data = f.getvalue()
valid_str ="".join(valid_list)
print(valid_str)
request.session["keepValidCode"]=valid_str
return HttpResponse(data)
def index(request):
return render(request,"index.html")
返回验证码并且把验证码写入session
三.点击submit提交
-ajax向后端提交
前端:(login.html.)
<script>
$("#subBtn").click(function () {
$.ajax({
url: "/login/",
type: "POST",
data: {
"username": $("#username").val(),
"password": $("#password").val(),
"validCode": $("#validCode").val(),
"csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(),
},
success: function (data) {
console.log(data);
var response = JSON.parse(data);
if (response["is_login"]) {
location.href = "/index/"
}
else {
$(".error").html(response["error_msg"]).css("color", "red")
}
}
})
})
</script>
后端:(在views中:)
-判断是否是ajax请求
if request.is_ajax():
- 获取用户名 密码 验证码
-username = request.POST.get("username")
-password = reuqest.POST.get("password")
-validCode = request.POST.get("validCode")
-判断验证用户信息是否存在
-login_response = {"is_login":False,"error_msg":None}
- 前端获取到的验证码和后端session的验证码是否相同
如果相同:
用户名和密码和数据库中是否匹配
如果不同:
obj[error_msg] = "username or password error"
返回前端
if validCode.upper() == request.session.get("keepValidCode").upper():
user = auth.authenticate(username=username, password=password)
if user:
login_response["is_login"] = True
auth.login(request, user)
else:
login_response["error_msg"] = "username or password error"
else:
login_response["error_msg"] = "validCode error"
import json
return HttpResponse(json.dumps(login_response))
return render(request, "login.html")
2.注册
- urls
-前端页面中写 username ,password,password,email,头像
-form组件创建注册页面
-widget的作用是,如果不加widget生成的前端标签是原生的input框,加上之后会变成渲染之后的
-eg:username,password,repeat_pwd,email
class RegForm(forms.Form):
email = forms.EmailField(widget=widgets.EmailInput(
attrs={"class": "form-control", "placeholder": "email"}
))
....还有username,password,repeat_pwd
如果form中有这些字段,则可以在前端页面中{{form_obj.username}},{{form_obj.password}}这样的方式取到值
-验证每个字段
- clean_username(self):(用到了局部钩子)
cleaned_data它代表的是一个字典
-ret=models.UserInfo.objects.filter(username=self.cleaned_data.get("username"))
if not ret: #校验字段
return self.cleaned_data.get("username")
else:
raise ValidationError("用户名已注册")
-检查数据库中是否有username
-如果没有,验证的那个字段,如果有这个username,则返回cleaned_data取到的值,如果已经存在该用户,就走ValidationError,显示error信息
- clean_password(self):(用到了局部钩子)
-同上方法验证,但需要注意,这个判断密码不能全是数字
def clean_validCode(self):(用到全局钩子)
-前端注册页面
-上一步在后端上传的form对象渲染了username,password,email
-生成头像
-<img src="/static/img/default.png" alt="" id="avatar_img">
-<input type="file" class="form-control" id="avatar_file">
(生成一个默认的灰色框头像,如用户点击上传头像,此时应该吧图片遮到上传的文件上面,
这里还有让parent设置成相对定位,children设置绝对定位,还有一点,应该不让灰色框隐藏,
而是让他的透明度为0)
-头像预览
-找到头像标签,用到change事件,用一个变量去接受当前拿到的文件,然后对去到该文件的路径,让他付给this.result
$("#avatar_file").change(function () {
var ele_file=$(this)[0].files[0]; //拿到当前点击的文件
var reader=new FileReader(); //创建一个新对象
reader.readAsDataURL(ele_file);
reader.onload=function (){
$("#avatar_img")[0].src=this.result
}
});
- Ajax提交数据
-使用formdata是因为里面有二进制文件
- 上传二进制文件引入 FormData()
- FormData()对象追加键值对
-$("#avatar_file")[0].files[0]) # jquery转DOM对象,取files对象最近一次上传的文件
$.ajax({
url:"/reg/",
type:"POST",
data:formdata,
contentType:false,
processData:false,
headers:{"X-CSRFToken":$.cookie('csrftoken')}, //为了避免Forbedent禁止
success:function (data) {
console.log(data);
var data=JSON.parse(data);
//能拿到user代表注册成功,跳转到登录页面
if (data.user){
location.href="/login/"
}
//反之
else{
console.log(data.errorsList);
$.each(data.errorsList,function (i,j) {
console.log(i,j);
$span=$("<span>");
$span.addClass("pull-right").css("color","red");
$span.html(j[0]);
$("#id_"+i).after($span).parent().addClass("has-error");
if (i=="__all__"){
$("#id_repeat_pwd").after($span)
}
})
}
注释:i为出错form组件字段、j为报错
each循环报错信息、新建span标签,给其增加样式(右漂浮,红色)
span的内容为报错信息
给出错的input标签后边添加span标签,并使其父级标签has-error
如果i使__all__:将报错添加到重新输入密码后边的span中
-后端注册(views中)
-判断是否是is_ajax请求
-接收从前端提交过来的数据
-form验证
实例化对象,然后进行校验,将校验的结果和数据库进行匹配验证,获取校验结果,cleaned_data是一个字典的形式,
如果校验失败,则走errors错误信息的列表
form_obj=forms.RegForm(request.POST) #接收从前端提交来的数据,规则和数据放在一起
if form_obj.is_valid():(开始校验,并获取校验结果)
username = form_obj.cleaned_data["username"]
password = form_obj.cleaned_data["password"]
email = form_obj.cleaned_data.get("email")
avatar_img = request.FILES.get("avatar_img")
................
-setting.py 如果只在这里设置 不在前端设置 用户接收不到文件
MEDIA_ROOT=os.path.join(BASE_DIR,"app01","media")
MEDIA_URL="/media/"
-urls.py
# media 配置
from django.views.static import serve
from blog import settings
url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),