BBS项目表设计
BBS项目表设计
-
CBV添加装饰器
from django.views import View # method_decorator @method_decorator(login_auth, name='get') # 第二种方式 class IndexView(View): @method_decorator(login_auth) # 第三种方式 def dispatch(self, request, *args, **kwargs) @method_decorator(login_auth) # 第一种方式 def get(self): pass
-
csrf跨站请求
1. form表单 {% csrf_token %} 2.ajax # 第一种方式 利用标签查找页面的随机字符串 data:{ 'username':'zhang', 'csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()}, # 第二种方式 利用模板语法 data:{ 'username':'zhang', 'csrfmiddlewaretoken': '{{ csrf_token }}'},#} # 第三种方式引入一个js文件直接复制就好了 #相关装饰器 csrf_protect : 需要验证 csrf_exempt:不需要验证 在CBV中,针对csrf_protect三种添加方式都可以 针对csrf_exempt,第一种方式,第二种方式都不行,第三种方式可以 第一种是在类里函数的上面加装饰器 第二种是在类上面加装饰器 第三种是在类里重写父类的dispatch方法 再次方法上面加
-
auth模块
from django.contrib import auth 1. 登录: auth.authenticate(request) # 验证用户名和密码是否正确 ''' 1. 自动会从auth_user表中查询数据 2. 密码自动加密进行比较 3. 用户名和密码必须同时传入 ''' # 保存用户信息 auth.login(rqeuest, user_obj) # request.session[key] = user_obj ''' 在全局任何地方,只要是能够拿到request对象的地方,都可以通过request.user取到用户对象 ''' 2. 验证是否登录 request.user.is_authenticate() 3. 验证登录的装饰器 @login_required 4. 修改密码 # 验证老密码是否正确 is_right = request.user.check_password(old_password) # 修改密码 request.user.set_password(new_password) # 只是修改了数据属性 request.user.save() # 真正的操作数据库 5. 注销用户 auth.logout(request) 6. 注册用户 User User.objects.create() # 密码不加密 User.objects.create_user() # 密码加密
# 前提:如果你已经执行了数据库迁移命令,这个时候就不能在扩展auth_user表了 # 设计表阶段就要明确需不需要扩展表 from django.contrib.auth.models import User 1. 扩展auth_user表要继承AbstractUser类 auth_user表不会创建出来了 会出现一个新的表 你的类的名字就是表名 2. 扩展字段不要动原来的字段,你只需要在继承的类中写你自己想要扩展的字段 3. 生成一个新表,该表有原来的字段加上你扩展出来的字段 4. 在settings.py中加个配置: AUTH_USER_MODEL = '应用名.表名' 5. 扩展表之后,auth_user表就没有了
-
需求分析(仿照博客园)
需要七张表 1.扩展auth_user表(继承abstractuser) phone 电话 avatar 头像 creattime 创建时间 # 外键字段 blog 一对一 #一对一个人站点表 2.站点表 blog site_name 站点名称 site_title 站点标题 site_theme 站点主题 css样式 3.标签表 name 标签名 外键字段 多个标签对一个站点 一对多站点表 4.分类表 name 分类名 #外键字段 一对多站点表 (多个分类对一个站点) 5.文章表 title 标题 desc 简介 content 内容 create_time 创建时间 #####优化字段######### ''' 下面这几个字段可以从其他表查询计算得出,但是频繁跨表查询 效率低 所以自己写三个 为了提高效率 up_num 点赞数 down_num 点踩数 comment_num 评论数 ''' # 外键字段 一对多站点表 (多个文章对应一个站点) 多对多文章标签 (一个文章有多个标签 一个标签有多个文章) 一对多文章分类 (一个文章一个分类 一个分类多个文章) 6.点赞点踩表 (记录哪个用户给哪篇文章点了赞还是点了踩) user foreignkey(to='User') article foreignkey(to='Article') is_up booleanfiled #外键字段 id user is_up 1 1 1 2 2 0 7.文章评论表(记录哪个用户给那篇文章写了那些评论内容) user foreignkey(to='User') article foreignkey(to='Article') content 评论内容charfiled comment_time 评论时间datafiled #自关联 自己跟自己关联 可以为空 #parent_id ForeignKey(to='Comment', null=True) #orm提供的专门自关联写法 里面存放的是跟评论的主键值 parent_id ForeignKey(to='self', null=True) 根评论与子评论的概念 # 根评论就是评论这篇文章的 # 子评论 1. PHP是世界上最好的语言 1.1 python才是 1.2 你滚蛋
-
创建数据表(核心)
创建数据库bbs settings 配置连接数据库 #先写普通字段在写外键字段 from django.db import models from django.contrib.auth.models import AbstractUser #用户表 class UserInfo(AbstractUser): phone=models.BigIntegerField(verbose_name='手机号',null=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 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 Tag(models.Model): name=models.CharField(verbose_name='文章标签',max_length=32) #外键字段 一对多 blog=models.ForeignKey(to='Blog',null=True) #分类表 class Category(models.Model): name=models.CharField(verbose_name='文章分类',max_length=32) # 外键字段 一对多 blog = models.ForeignKey(to='Blog', null=True) #文章表 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') )#多对多 文章和标签表 #第三种关系表 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 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)
-
注册功能
##views
from django.shortcuts import render
from django.http import JsonResponse
from app01 import models
# Create your views here.
#注册功能
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')
-
注册前端页面
<!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="">用户名</label> <input type="text" id="username" class="form-control"> </div> <div class="form-group"> <label for="">密码</label> <input type="password" id="pwd" class="form-control"> </div> <div class="form-group"> <label for="">确认密码</label> <input type="password" id="re_pwd" class="form-control"> </div> <div class="form-group"> <label for="">邮箱</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>