BBS项目之登录页面首页
BBS项目之登录页面首页
登录页面以及验证码
#登录功能
def login(request):
if request.is_ajax():
if request.method=='POST':
# 获取参数
back_dic={'code':200,'msg':'登陆成功'}
username=request.POST.get('username')
pwd=request.POST.get('pwd')
code=request.POST.get('code')
#验证参数
if not username:
back_dic['code']=301
back_dic['msg']='用户名未填写'
return JsonResponse(back_dic)
if not pwd:
back_dic['code']=302
back_dic['msg']='密码未填写'
return JsonResponse(back_dic)
if not code:
back_dic['code']=303
back_dic['msg']='验证码未填写'
return JsonResponse(back_dic)
if request.session.get('code').upper() != code.upper():
back_dic['code']=304
back_dic['msg']='验证码不正确'
return JsonResponse(back_dic)
# 业务逻辑 判断传进来的和数据库的是否一致
import hashlib
m = hashlib.md5()
m.update(pwd.encode('utf-8'))
pwd = m.hexdigest()
user_obj=models.UserInfo.objects.filter(username=username,password=pwd).first()
if not user_obj:
#为了防止撞库 知道用户名或者密码错误
back_dic['code'] = 305
back_dic['msg'] = '用户名或密码不正确'
return JsonResponse(back_dic)
#保存用户信息 session 当前登录的用户
request.session['id']=user_obj.id
request.session['username']=user_obj.username
#返回数据
back_dic['url']='/home/'
return JsonResponse(back_dic)
return render(request,'login.html')
#验证码
"""
图片相关的模块 先下载这个pillow
pip3 install pillow
"""
from PIL import Image, ImageDraw, ImageFont
"""
Image:生成图片
ImageDraw:能够在图片上乱涂乱画 生成空图片 在上面写东西
ImageFont:控制字体样式
"""
from io import BytesIO, StringIO
"""
内存管理器模块
BytesIO:临时帮你存储数据 返回的时候数据是二进制
StringIO:临时帮你存储数据 返回的时候数据是字符串
"""
import random
def get_random():
return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
def get_code(request):
# 最终步骤4:写图片验证码
img_obj = Image.new('RGB', (430, 35), get_random())
img_draw = ImageDraw.Draw(img_obj) # 产生一个画笔对象
img_font = ImageFont.truetype('static/font/111.ttf', 30) # 字体样式 大小
# 随机验证码 五位数的随机验证码 数字 小写字母 大写字母
code = ''
for i in range(4):
random_upper = chr(random.randint(65, 90)) #A--Z
random_lower = chr(random.randint(97, 122)) #a--z
random_int = str(random.randint(0, 9)) #0--9
# 从上面三个里面随机选择一个
tmp = random.choice([random_lower, random_upper, random_int])
# 将产生的随机字符串写入到图片上
"""
为什么一个个写而不是生成好了之后再写
因为一个个写能够控制每个字体的间隙 而生成好之后再写的话
间隙就没法控制了
"""
img_draw.text((i * 60 + 60, -2), tmp, get_random(), img_font)
# 拼接随机字符串
code += tmp
print(code)
# 随机验证码在登陆的视图函数里面需要用到 要比对 所以要找地方存起来并且其他视图函数也能拿到
request.session['code'] = code
io_obj = BytesIO()
img_obj.save(io_obj, 'png')
return HttpResponse(io_obj.getvalue())
注册功能
#注册功能
def register(request):
if request.method == 'POST':
# 提前定义一个json格式的字典类型 ajax一般返回json格式
back_dic = {'code': 200, 'msg': '注册成功'}
####1.接受参数
username = request.POST.get('username')
pwd = request.POST.get('pwd')
re_pwd = request.POST.get('re_pwd')
email = request.POST.get('email')
avatar = request.FILES.get('myfile')
#2.验证参数 前端验证可有可无 先验证不符合条件的
if not username:
back_dic['code']=201
back_dic['msg']='用户名必须填写'
return JsonResponse(back_dic)
if not pwd:
back_dic['code'] = 202
back_dic['msg'] = '密码必须填写'
return JsonResponse(back_dic)
if not pwd == re_pwd:
back_dic['code'] = 203
back_dic['msg'] = '两次密码输入不一致'
return JsonResponse(back_dic)
if not email:
back_dic['code'] = 204
back_dic['msg'] = '邮箱未填写'
return JsonResponse(back_dic)
#3.查询数据库是不是有这个用户名 是否重复
res=models.UserInfo.objects.filter(username=username).first()
if res:
back_dic['code'] = 205
back_dic['msg'] = '用户已存在'
return JsonResponse(back_dic)
#4.头像是否上传 业务逻辑
data_dic={}
if avatar:
data_dic['avatar']=avatar
data_dic['username'] = username
import hashlib
m=hashlib.md5()
m.update(pwd.encode('utf-8'))
pwd=m.hexdigest()
data_dic['password'] = pwd
data_dic['email'] = email
#5.入库 **字典打散成关键字参数
models.UserInfo.objects.create(**data_dic)
back_dic['url']='/login/'
return JsonResponse(back_dic) #返回格式化后的数据
return render(request, 'register.html')
修改密码
#修改密码 加登录装饰器
def set_pwd(request):
if request.is_ajax():
if request.method=='POST':
back_dic = {'code': 200, 'msg': '修改密码成功'}
old_pwd=request.POST.get('old_pwd')
new_pwd=request.POST.get('new_pwd')
re_pwd=request.POST.get('re_pwd')
#先验证旧密码是否正确
old_pwd=hash_pwd(old_pwd)
res=models.UserInfo.objects.filter(username=request.session.get('username'),password=old_pwd).first()
if not res:
back_dic['code']=1001
back_dic['msg']='原密码不正确'
return JsonResponse(back_dic)
if new_pwd !=re_pwd:
back_dic['code'] = 1002
back_dic['msg'] = '两次密码输入不一致'
return JsonResponse(back_dic)
new_pwd=hash_pwd(new_pwd)
#写入数据库
models.UserInfo.objects.filter(pk=request.session.get('id')).update(password=new_pwd)
for i in back_dic:
print(i,back_dic[i])
return JsonResponse(back_dic)
-
注册页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> {% load static %} <script src="{% static 'layer-v3.5.1/layer/layer.js' %}"></script> {# <script src="{% static 'js/mysetup.js' %}"></script>#} </head> <body> <div class="container-fluid"> <div class="row"> <h1 class="text-center">注册页面</h1> <div class="col-md-8 col-md-offset-2"> <form action=""> {# {% csrf_token %}#} <div class="form-group"> <label for="username">用户名</label> <input type="text" id="username" class="form-control"> </div> <div class="form-group"> <label for="pwd">密码</label> <input type="password" id="pwd" class="form-control"> </div> <div class="form-group"> <label for="re_pwd">确认密码</label> <input type="password" id="re_pwd" class="form-control"> </div> <div class="form-group"> <label for="email">邮箱</label> <input type="email" id="email" class="form-control"> </div> <div class="form-group"> <label for="myfile">头像 {% load static %} <img src="{% static 'img/default.jpg' %}" id="myimg" alt="" width="112" style="margin-left: 30px"> </label> <input type="file" id="myfile" class="form-control" style="display: none"> </div> <input type="button" class="btn btn-success btn-block pull-right" value="注册"> </form> </div> </div> </div> <script> //头像实时展示 借助于文件阅读器 $('#myfile').change(function () { //1.创建文件阅读器对象 var myFileReadobj = new FileReader(); //2.获取图片数据 var myImgObj = $('#myfile')[0].files[0]; //3.图片数据交给文件阅读器读取 myFileReadobj.readAsDataURL(myImgObj) //这句是异步操作(不等他的结果) io操作 //放在onload 方法 等外面代码执行完 在读取里面的 myFileReadobj.onload = function () { //4.改变img的src attr拿某个标签的内部属性 $('#myimg').attr('src', myFileReadobj.result) } }) $('.btn').click(function () { //前端验证 var username = $('#username').val(); var pwd = $('#pwd').val(); var re_pwd = $('#re_pwd').val(); var email = $('#email').val(); if (!username) { layer.msg('请输入用户名') return } if (!pwd) { layer.msg('请输入密码') return } if (!re_pwd) { layer.msg('确认密码未输入') return } if (!email) { layer.msg('请输入邮箱') return } var formDataObj = new FormData() formDataObj.append('username', username); formDataObj.append('pwd', pwd); formDataObj.append('re_pwd', re_pwd); formDataObj.append('email', email); //添加文件数据 formDataObj.append('myfile', $('#myfile')[0].files[0]); $.ajax({ url: '', type: 'post', //用formdata提交需要指定 contentType: false, processData: false, data: formDataObj, success: function (args) { if (args.code == 200) { layer.msg(args.msg, {icon: 1}, function () { location.href = args.url }) } else { layer.msg(args.msg) } } }) }) </script> </body> </html>
-
登录页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> {% load static %} <script src="{% static 'layer-v3.5.1/layer/layer.js' %}"></script> {# <script src="{% static 'js/mysetup.js' %}"></script>#} </head> <body> <div class="container-fluid"> <div class="row"> <h1 class="text-center">登录界面</h1> <div class="col-md-8 col-md-offset-2"> <form action=""> <div class="form-group"> <label for="">用户名:</label> <input type="text" id="username" class="form-control"> </div> <div class="form-group"> <label for="">密码:</label> <input type="text" id="pwd" class="form-control"> </div> <div class="form-group"> <label for="">验证码:</label> <div class="row"> <div class="col-md-6"> <input type="text" id="code" class="form-control"> </div> <div class="col-md-6"> <img src="/get_code/" id="id_img" alt="" style="width: 475px;height: 33px;"> </div> </div> </div> <input type="button" class="btn btn-primary btn-block" value="登录"> </form> </div> </div> </div> <script> $('#id_img').click(function () { var old=$(this).attr('src') $(this).attr('src',old += '?') }) $('.btn').click(function () { var username=$('#username').val() var pwd=$('#pwd').val() var code=$('#code').val() //验证参数 if (!username){ layer.msg('请输入用户名') return } if (!pwd){ layer.msg('请输入密码') return } if (!code){ layer.msg('请输入验证码') return } $.ajax({ url:'', type:'post', data:{'username':username,'pwd':pwd,'code':code}, success:function (res) { if (res.code==200){ layer.msg(res.msg,{icon: 1},function () { location.href=res.url; }); }else { layer.msg(res.msg,{icon: 2}); } } }) }) </script> </body> </html>
-
主界面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> {% load static %} <script src="{% static 'layer-v3.5.1/layer/layer.js' %}"></script> {# <script src="{% static 'js/mysetup.js' %}"></script>#} </head> <body> <nav class="navbar navbar-inverse"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">BBS</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="#">博客 <span class="sr-only">(current)</span></a></li> <li><a href="#">Link</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> <li role="separator" class="divider"></li> <li><a href="#">One more separated link</a></li> </ul> </li> </ul> <form class="navbar-form navbar-left"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search"> </div> <button type="submit" class="btn btn-default">Submit</button> </form> <ul class="nav navbar-nav navbar-right"> {% if request.session.username %} <li><a href="#">{{ request.session.username }}</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">设置 <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#" data-toggle="modal" data-target="#myModal">修改密码</a></li> <li><a href="#">账号管理</a></li> <li><a href="/loginout/">退出登录</a></li> </ul> </li> {% else %} <li><a href="/register/">注册</a></li> <li><a href="/login/">登录</a></li> {% endif %} <!-- Modal --> <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel">Modal title</h4> </div> <div class="modal-body"> <div class="row"> <div class="form-group"> <label for="">原密码</label> <input type="" id="old_pwd" class="form-control"> </div> <div class="form-group"> <label for="">新密码</label> <input type="text" id="new_pwd" class="form-control"> </div> <div class="form-group"> <label for="">确认密码</label> <input type="text" id="re_pwd" class="form-control"> </div> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">取消</button> <button type="button" class="btn btn-primary commit">确认</button> </div> </div> </div> </div> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <div class="container-fluid"> <div class="col-md-2"> <div class="panel panel-primary "> <div class=" panel-body "> Panel content </div> <div class="panel-footer">Panel footer</div> </div> <div class="panel panel-primary"> <div class="panel-body"> Panel content </div> <div class="panel-footer">Panel footer</div> </div> <div class="panel panel-primary"> <div class="panel-body"> Panel content </div> <div class="panel-footer">Panel footer</div> </div> </div> <div class="col-md-8"> {% for aritcle in aritcle_list %} <ul class="media-list"> <li class="media"> <h4 class="media-heading"><a href="">{{ aritcle.title }}</a></h4> <div class="media-left"> <a href="#"> <img class="media-object" src="/static/img/default.jpg" alt="..." width="100px" height="100px"> </a> </div> <div class="media-body"> {{ aritcle.desc }} </div> <br> <div> <span><a href="">{{ aritcle.blog.userinfo.username }} </a></span> <span>{{ aritcle.create_time|date:'Y-m-d ' }} </span> <span><span class="glyphicon glyphicon-thumbs-up"></span>({{ aritcle.up_num }}) </span> <span><span class="glyphicon glyphicon-thumbs-down"></span>({{ aritcle.down_num }}) </span> <span><span class="glyphicon glyphicon-comment"></span>({{ aritcle.comment_num }}) </span> </div> </li> <hr> </ul> {% endfor %} </div> <div class="col-md-2"> <div class="panel panel-primary"> <div class="panel-body"> Panel content </div> <div class="panel-footer">Panel footer</div> </div> <div class="panel panel-primary"> <div class="panel-body"> Panel content </div> <div class="panel-footer">Panel footer</div> </div> <div class="panel panel-primary"> <div class="panel-body"> Panel content </div> <div class="panel-footer">Panel footer</div> </div> </div> </div> <script> $('.commit').click(function () { var old_pwd = $('#old_pwd').val(); var new_pwd = $('#new_pwd').val(); var re_pwd = $('#re_pwd').val(); //验证参数 if (!old_pwd) { layer.msg('请输入旧密码') return } if (!new_pwd) { layer.msg('请输入新密码') return } if (!re_pwd) { layer.msg('请再次输入密码') return } $.ajax({ url: '/set_pwd/', type: 'post', data: {'old_pwd': old_pwd, 'new_pwd': new_pwd, 're_pwd': re_pwd}, success: function (res) { if (res.code == 200) { layer.msg(res.msg, {icon: 1}, function () { location.reload(); }); } else { layer.msg(res.msg, {icon: 2}); } } }) }) </script> </body> </html>
-
admin
from django.contrib import admin
# Register your models here.
from app01 import models
#想在django自带的后台管理系统管理数据,就要在这个里面注册
#注册了之后 自带后端页面显示这个userinfo
admin.site.register(models.UserInfo)
admin.site.register(models.Blog)
admin.site.register(models.Article)
admin.site.register(models.Category)
admin.site.register(models.Tag)
admin.site.register(models.Comment)
admin.site.register(models.UpAndDown)
admin.site.register(models.Article2Tag)
models
from django.db import models
from django.contrib.auth.models import AbstractUser
#用户表
class UserInfo(AbstractUser):
#前面这个限制数据库,后面这个前端也限制
phone=models.BigIntegerField(verbose_name='手机号',null=True,blank=True)
avatar=models.FileField(upload_to='static/img',default='static/img/default.jpg')
'''
以后用户上传头像会直接上传到'static/img'路径下
如果没有上传,使用默认的:static/img/default.png
'''
create_time=models.DateTimeField(auto_now_add=True)
#外键字段 一对一
blog=models.OneToOneField(to='Blog',null=True)
#让他后台管理显示中文标示
class Meta:
verbose_name_plural='用户表'
#站点表
class Blog(models.Model):
site_name=models.CharField(verbose_name='站点名称',max_length=32)
site_title=models.CharField(verbose_name='站点标题',max_length=32)
#存css或者js文件的路径
site_theme=models.CharField(verbose_name='站点样式',max_length=64)
class Meta:
verbose_name_plural='站点表'
def __str__(self):
return self.site_name
#标签表
class Tag(models.Model):
name=models.CharField(verbose_name='文章标签',max_length=32)
#外键字段 一对多
blog=models.ForeignKey(to='Blog',null=True)
class Meta:
verbose_name_plural='标签表'
def __str__(self):
return self.name
#分类表
class Category(models.Model):
name=models.CharField(verbose_name='文章分类',max_length=32)
# 外键字段 一对多
blog = models.ForeignKey(to='Blog', null=True)
class Meta:
verbose_name_plural='分类表'
def __str__(self):
return self.name
#文章表
class Article(models.Model):
title=models.CharField(verbose_name='文章标题',max_length=64)
desc=models.CharField(verbose_name='文章简介',max_length=255)
#文章内容比较多一般使用 TextField
content=models.TextField(verbose_name='文章内容')
create_time=models.DateField(auto_now_add=True)
#数据库优化字段
up_num=models.BigIntegerField(verbose_name='点赞数',default=0)
down_num=models.BigIntegerField(verbose_name='点踩数',default=0)
comment_num=models.BigIntegerField(verbose_name='评论数',default=0)
#外键字段
blog=models.ForeignKey(to='Blog',null=True)#一对多 文章和站点
category=models.ForeignKey(to='Category',null=True)#一对多 文章和分类表
tags=models.ManyToManyField(to='Tag',
through='Article2Tag',
through_fields=('article','tag')
)#多对多 文章和标签表
class Meta:
verbose_name_plural='文章表'
def __str__(self):
return self.title
#第三种关系表 manytomany
class Article2Tag(models.Model):
article=models.ForeignKey(to='Article')
tag=models.ForeignKey(to='Tag')
#点赞点踩表
class UpAndDown(models.Model):
user = models.ForeignKey(to='UserInfo')
article = models.ForeignKey(to='Article')
is_up = models.BooleanField() #传布尔值 存0/1
class Meta:
verbose_name_plural='点赞点踩表'
#评论表
class Comment(models.Model):
user = models.ForeignKey(to='UserInfo')
article = models.ForeignKey(to='Article')
content= models.CharField(verbose_name='评论内容',max_length=512)
comment_time=models.DateTimeField(verbose_name='评论时间',auto_now_add=True)
#加null等于True 是因为有些评论就是跟评论,他没有子评论
parent = models.ForeignKey(to='self', null=True)
class Meta:
verbose_name_plural='评论表'