BBS总结
表设计
from django.db import models
from django.contrib.auth.models import AbstractUser # Create your models here.
class UserInfo(AbstractUser):
nid=models.AutoField(primary_key=True)
# blank=True admin中改字段可以不填,null=True是数据库层面可以为空
telephone = models.BigIntegerField(null=True,blank=True)
# auto_now_add 创建时自动添加当前时间
create_date = models.DateField(auto_now_add=True)
# upload_to需要传一个路径
# default 默认头像的路径
avatar = models.FileField(upload_to='avatar/', default='avatar/default.png')
# 跟Blog表一对一
blog = models.OneToOneField(to='Blog', to_field='nid',null=True)
class Meta:
verbose_name='用户表'
verbose_name_plural = verbose_name
# 个人站点表
class Blog(models.Model):
nid = models.AutoField(primary_key=True)
site_name = models.CharField(max_length=32)
site_title = models.CharField(max_length=64)
# 存css文件的路径
theme = models.CharField(max_length=32)
def __str__(self):
return self.site_name class Category(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
blog = models.ForeignKey(to='Blog', to_field='nid') class Tag(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
blog = models.ForeignKey(to='Blog', to_field='nid')
def __str__(self):
return self.name class Article(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField(max_length=64,verbose_name='文章标题')
desc = models.CharField(max_length=255)
# 存大文本
content = models.TextField()
create_time = models.DateTimeField(auto_now_add=True)
# 跟站点表一对多
blog = models.ForeignKey(to='Blog', to_field='nid',null=True)
# 跟分类一对多
category = models.ForeignKey(to='Category', to_field='nid',null=True)
# 跟标签多对多,手动创建第三张表
tag = models.ManyToManyField(to='Tag', through='Article2Tag', through_fields=('article', 'tag')) # 后来想到的
# 评论数,点赞,点踩数
comment_num=models.IntegerField(default=0)
up_num=models.IntegerField(default=0)
down_num=models.IntegerField(default=0)
def __str__(self):
return self.title class Article2Tag(models.Model):
nid = models.AutoField(primary_key=True)
article = models.ForeignKey(to='Article', to_field='nid')
tag = models.ForeignKey(to='Tag', to_field='nid') #谁对哪篇文章,点赞还是点踩
class UpAndDown(models.Model):
nid = models.AutoField(primary_key=True)
user = models.ForeignKey(to='UserInfo')
article = models.ForeignKey(to='Article', to_field='nid')
is_up = models.BooleanField() #评论对评论自关联,
#谁,什么时候,对哪篇文章,评论了什么内容,父评论是谁
class Comment(models.Model):
nid = models.AutoField(primary_key=True)
user = models.ForeignKey(to='UserInfo')
article = models.ForeignKey(to='Article', to_field='nid')
content = models.CharField(max_length=255)
# 评论时间
create_time=models.DateTimeField(auto_now_add=True)
# parent =models.ForeignKey(to='Comment',to_field='nid')
# 自关联,存父评论id
parent = models.ForeignKey(to='self', to_field='nid',null=True)
# parent =models.IntegerField()
1 登陆功能:
-图形验证码
-ajax提交
-认证用的是auth
-认证通过,login
1 forms组件
1 定义
from django import forms
from django.forms import widgets
from django.core.exceptions import ValidationError
# 2 写一个类
class RegForm(forms.Form):
# 3 写属性
name=forms.CharField(max_length=8,min_length=3,label='用户名',error_messages={'max_length':'超长了'},
widget=widgets.TextInput(attrs={'class':'form-control'})
) # 4 局部钩子函数
def clean_name(self):
name=self.cleaned_data.get('name')
if name.startswith('sb'):
raise ValidationError('不能以sb开头')
else:
# 切记,如果正确,一定要返回name
return name # 5 全局钩子函数
def clean(self):
#一系列逻辑判断
#如果校验通过:返回cleaned_data
#如果校验不通过:raise ValidationError('两次密码不一致'),错误放到__all__
pass
2 views中使用:
def test(request):
if request.method=='GET':
regform=RegForm()
else:
regform=RegForm(request.POST)
if regform.is_valid():
#一般情况需要存数据库了
pass
else:
error_all=regform.errors.get('__all__')
# error_all=regform.errors['__all__']
return render(request,'register.html',locals())
3 模板中使用
<form action=""> {% for foo in regform %}
{{ foo.label }}:{{ foo }} <span>{{ foo.errors.0 }}</span>
{% endfor %}
<input type="submit"> <span>{{ error_all }}</span> </form> 2 cookie和session
1 cookie:由服务器产生,存放在客户端浏览器上的键值对
2 django中使用cookie:
-设置值:
obj=HttpResponse('ok')
obj.set_cookie('key','value',max_age=10)
-取值:
request.COOKIES.get('key')
request.COOKIES['key']
-删除值:
obj=HttpResponse('ok')
obj.delete_cookie('key') 3 session:保存在服务器上的键值对
-设置值:
request.session['key']='value'
request.session['key1']='value1' 1 生成一个随机字符串:dasfasdf
2 在django_session表中存入dasfasdf {'key':'value','key1':value1} 超时时间
3 把sessionid:dasfasdf写入到cookie -取值:
request.session.get('key')
-删除值:
request.session.flush():全删除
request.session.delete():只删除数据库
-其它配置参数:
了解 3 Auth模块
1 Django自带的用户认证模块,可以快速的实现登录,注销,修改密码...
2 扩展auth表,需要继承AbstractUser
3 一定不要忘记在setting中配置:AUTH_USER_MODEL = "app名.UserInfo"
4 它提供的功能
-from django.contrib.auth import authenticate,login,logout
-用户认证:user=authenticate(username=lqz,password=123)
-用户一旦认证通过,调用login(request,user),以后从request.user中就能取出当前登录人对象
-退出:logout(request),request.user就是匿名用户
-校验是否通过认证(是否登录):request.user.is_authenticated()
-创建普通用户
-models.UserInfo.objects.create_user(username=lqz)
-创建超级用户
-models.UserInfo.objects.create_superuser(username=lqz)
-修改密码
-用user对象.set_password(新密码)
-一定要记住save
-校验密码
-check_password(password)
-登录认证装饰器(没有登陆的时候跳转)
-login_required(login_url='/login/')
-全局配置(在setting中配置):
LOGIN_URL = '/login/'
is_staff: 用户是否拥有网站的管理权限:create_superuser:is_staff是1
is_active: 是否允许用户登录, 设置为 False,可以在不删除用户的前提下禁止用户登录。 今日内容:
1 中间件
-是什么?中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能
-怎么用:
-自定义中间件:
1 写一个类,继承MiddlewareMixin,
2 在类中写方法:
process_request
3 在settings中配置 -5个方法(process_request,process_response)
******
process_request(self,request)
-执行顺序,settings中中间件自上而下执行
-请求来的时候会执行它
-request对象,就是本次请求的request对象,对它处理后,视图函数拿到的就是处理后的request对象 process_view(self, request, callback, callback_args, callback_kwargs)
-callback是视图函数,callback_args, callback_kwargs是视图函数的参数
-可以调用callback方法 process_template_response(self,request,response)(忘掉)
-只有视图函数返回的对象中有render方法的时候,才会执行
process_exception(self, request, exception)
-视图函数出错,会执行它
*****
process_response(self, request, response)
-执行顺序,settings中中间件自下而上执行
-响应走的时候,会执行它
-request对象,就是本次请求的request对象,response是响应对象(HttpResponse的对象) -如果process_request方法返回HttpResponse的对象,请求直接返回,按中间件方法执行顺序往回走 2 csrf
xss攻击/csrf或xsrf跨站请求伪造
使用:中间件不注释,form表单中写{% csrf_token %} 3 bbs表设计
-一个项目从无到有
1 需求分析
-登录ajax,图形验证码
-注册forms和ajax,上传头像,头像预览
-博客首页
-个人站点
-点赞,点踩
-评论
-根评论
-子评论
-后台展示
-添加文章
-防xss攻击
2 设计程序以及程序的架构
-Django
-数据库设计 3 分任务开发程序 4 测试
5 上线运行 -数据库设计
-用户表:UserInfo---auth模块
...
-telephone:手机号
-create_date:注册时间
-avatar:用户头像
-blog:跟Blog表一对一
-个人站点表:Blog
-site_name:站点名称
-site_title:站点标题
-theme:站点主题样式
-分类表:Category
-nid
-name:分类名称
-blog:属于哪个站点 一对多
-标签表:Tag
-nid
-name:标签的名称
-blog:属于哪个站点 一对多
-文章表:Article
-nid
-title:文章标题
-desc:文章摘要
-content:文章内容
-create_time:文章发布时间
-blog:文章属于哪个站点, 一对多
-category:文章分类 一对多
-tag:文章标签 多对多 -Article2Tag:文章跟标签的中间表
-nid
-article_id:文章id
-tag_id:标签id
-点赞点踩表:UpAndDown
-nid
-user:谁 一对多
-article:给那篇文章 一对多
-is_up:点赞或点踩
-评论表:Comment
-nid
-user:谁 一对多
-article:给那篇文章 一对多
-content:评论了什么内容
-parent_id:父评论的id 自关联 nid 用户id 文章id 内容 parent_id(父评论的id)
1 1 1 你好 null
2 2 1 写的真好 null
3 3 1 你傻么 1 作业:
1 csrf中间件不注释,用ajax提交post请求
2 用中间件实现只有登录了以后,才能访问order,userinfo这些路径,如果没有登录,重定向到登录页面
2 注册功能
-forms组件
-ajax提交
-错误信息渲染
1 注册:
-forms组件渲染页面
-头像预览
-点击img触发头像上传
-$("#myform").serializeArray()的使用
-jq的循环 $.each(循环的对象,匿名函数(两个参数)):
循环对象如果是个列表,匿名函数的两个参数,一个是索引,一个是索引对应的值
循环对象如果是个字典,匿名函数的两个参数,一个是key,一个是value
-上传文件:
processData: false,
contentType: false,
-错误信息渲染
-定时器 -reg_form.is_valid()走了它之后,cleaned_data中才有值
-2 登陆
-生成验证码
-Pillow
-生成图片
-在图片上写字
-指定写字的字体
-内存管理器BytesIO
-验证码保存在session中 -验证码刷新:
$("#id_imgcode")[0].src += '?' 127.0.0.1:8000/getcode/?random=随机数
3 首页
admin中添加数据要将用户与一个用户表进行关联
media的配置,设置用户上传头像路径和默认头像
开口:
url(r'^media/(?P<path>.*)', serve,{'document_root':settings.MEDIA_ROOT}),
-全部文章取出来(分页)for循环渲染
-首页设计:
-用户是否登陆
{% if request.user.is_authenticated %}
<li><a href="#">{{ request.user.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="#">修改密码</a></li>
<li><a href="#">修改头像</a></li>
<li role="separator" class="divider"></li>
<li><a href="/logout/">退出</a></li>
</ul>
</li>
{% else %}
<li><a href="/login/">登陆</a></li>
<li><a href="/register/">注册</a></li>
{% endif %}
-for循环显示所有文章
-文章作者显示:
-{{ article.blog.userinfo.username }}:通过文章,正向查询站点(blog),通过站点反向查询用户,通过用户取出姓名
-文章评论和点赞数显示:
-<span>评论({{ article.comment_set.count }})</span>
-<span>点赞({{ article.upanddown_set.count}})</span>
-通过文章反向查询(表名小写_set)所有评论,计算评论条数
比较复杂,所以用了在文章表中加入三个字段
comment_num=models.IntegerField(default=0)
up_num=models.IntegerField(default=0)
down_num=models.IntegerField(default=0)
-admin的使用(快速录入数据):
-注册表,才能在admin后台看到
admin.site.register(models.UserInfo)
admin.site.register(models.Blog)
admin.site.register(models.Tag)
admin.site.register(models.Category)
admin.site.register(models.Article)
admin.site.register(models.UpAndDown)
admin.site.register(models.Comment)
-表名的中文显示:
class Meta:
verbose_name='用户表'
verbose_name_plural = verbose_name
-字段的中文显示(verbose_name):
title = models.CharField(max_length=64,verbose_name='文章标题')
-admin表单提交,是否必填(blank),注意区分null=True
-telephone = models.BigIntegerField(null=True,blank=True) -mediaroot配置
-media文件:用户上传的静态文件
-static文件:网站所用的静态文件
-在settings中配置:MEDIA_ROOT = os.path.join(BASE_DIR, 'media'),用户上传的文件放到里面
-在路由中写: url(r'^media/(?P<path>.*)', serve,{'document_root':settings.MEDIA_ROOT}),
4 个人站点
-文章展示(当前站点的所有文章)
-左侧标签显示
-三个分组查询,TruncMonth
-抽取成inclusion_tag
-左侧过滤
-个人站点:
-路由:url(r'^(?P<username>\w+)',views.site),
-视图函数:
def site(request,username):
#通过名字取数据库查询此人是否存在,如果存在,返回此人个人站点,如果不存在,返回404
user=models.UserInfo.objects.filter(username=username).first()
if not user:
return render(request,'error.html')
# 取到此人个人站点
blog=user.blog
# 取出该站点下所有文章(从blog取article,反向查询,一对多,按表名小写_set.all())
article_list=blog.article_set.all()
return render(request,'site.html',locals())
-页面样式显示:(动态显示)
<link rel="stylesheet" href="/static/css/{{ blog.theme }}"> -补充:
如果想django不自动加斜杠,需要配置APPEND_SLASH=False
-防盗链:
-就是根据refer信息 -自定义session(在中间件中处理)
-自己的图片防盗链(头三次,可以访问)
-访问频率控制(一分钟只能,同一个ip地址只能访问3次)
-设置一个全局变量,记录60sip 访问次数
-个人站点左侧显示
-截断表分析
id 时间 文章内容 month
1 2019-01-25 03:04:07.844138 111 2019-01
2 2018-12-01 03:04:54.000000 222 2018-12
3 2018-12-01 03:05:17.000000 333 2018-12
4 2018-11-01 03:05:38.000000 444 2018-11
-官方提供
from django.db.models.functions import TruncMonth
Sales.objects
.annotate(month=TruncMonth('timestamp')) # Truncate to month and add to select list
.values('month') # Group By month
.annotate(c=Count('id')) # Select the count of the grouping
.values('month', 'c') # (might be redundant, haven't tested) select month and count -重点总结:
-查询当前站点分类下的文章数
annotate 方法不局限于用于本文提到的统计分类下的文章数,你也可以举一反三,只要是两个 model 类通过 ForeignKey 或者 ManyToMany 关联起来,那么就可以使用 annotate 方法来统计数量。
category_ret = models.Category.objects.filter(blog=blog).annotate(c=Count('article')).values_list('name', 'c')
-查询当前站点标签下的文章数
tag_ret=models.Tag.objects.filter(blog=blog).annotate(c=Count('article')).values_list('name','c')
-查询当前站点下每个月份下的文章数
-month_ret=models.Article.objects.filter(blog=blog).annotate(month=TruncMonth('create_time')).values('month').annotate(c=Count('pk')).values_list('month','c')
-前端显示:
{% for category in category_ret %}
<p><a href="">{{ category.0 }}({{ category.1 }})</a></p>
{% endfor %}
-个人站点过滤
-抽取成inclusion_tag
-路由设计:
<p><a href="/{{ username }}/category/{{ category.2 }}">{{ category.0 }}({{ category.1 }})</a></p>
左边栏
5 文章详情
-继承了母版
-marksafe展示html
6 点赞点踩
-事务
-点赞点踩
-前端:
-样式:从博客园扣过来的
-ajax提交数据
-谁对哪篇文章点赞或点赞
-只写一个ajax,取出当前点击div内的span,后续直接在span上加一
-后端:
-先判断是否登录
-再判断是否已经点过
-去article表中修改点赞或点踩数
-去点赞点踩表中插入一条数据
7 评论
-根评论
-根评论提交
-根评论render显示
-根评论ajax显示
-子评论
-子评论提交
-子评论render显示
-子评论ajax显示
-根评论
-提交
-跟点赞点踩类似
-render显示
-后端取出所有评论
-模板中渲染: <ul class="list-group">
-日期过滤:comment.create_time|date:'Y-m-d H:i:s' -ajax显示:
-es6的字符串替换语法:`asdfasfd ${变量名}`,变量需要先定义
-$(".list-group").append(ss) 拼完追加到后面 -es6字符串替换
'you is %s'%'big'
var user_name='lqz'
ss=`
<li class="list-group-item">
<p>
<span>${ user_name }</span>
<span>${ time }</span>
</p>
${content}
</li>
`
1 子评论提交
-点击回复按钮,1 获取parent_id 2在文本框中输入:@人名 回车
-提交的时候:如果是子评论,需要切掉头部
var index=content.indexOf('\n')+1
content=content.slice(index)
-提交的时候:需要把parent_id提交到后台
2 子评论render显示
-判断是否有父评论,如果有,显示父评论的人名
-@{{ comment.parent.user.username }}
3 子评论的ajax显示
-根据parent_id是否有值,判断要拼接的html样式
-评论提交成功,parent_id的值要置为空
-后台:如果是子评论格式,需要返回父评论评论人的名字
子评论
8 后台文章展示
-table的展示
9 新增文章
-富文本编辑器使用
-富文本编辑器上传图片
-处理xss攻击(bs4)
5 文章添加
-富文本编辑器
-从官网下载,放到static文件夹下
-window.editor = K.create('#id_content')
-其它参数,具体看文档
-上传图片,携带csrf
uploadJson:'/add_img/',
extraFileUploadParams : {
csrfmiddlewaretoken : '{{ csrf_token }}',
}
-xss攻击(bs4)
-通过bs4模块,取出script标签,删除decompose()
-取出html中150个字符:soup.text[0:150]
beautifulsoup4 模块
-解析html页面的
-爬虫中用的多 -局部禁用csrf,局部使用
from django.views.decorators.csrf import csrf_protect,csrf_exempt
@csrf_exempt 局部禁用,前提是csrf中间件使用着
@csrf_protect 局部使用,前提是csrf中间件没有使用
-CBV加装饰器
1 可以加在方法上
@method_decorator(auth_login)
2 可以加在类上
-@method_decorator(auth_login,name='dispatch'):全部使用
-@method_decorator(auth_login,name='get'):只在get上使用
3 csrf的装饰器,只能加在类上
@method_decorator(csrf_exempt,name='dispatch')
BBS总结的更多相关文章
- Python之路【第十八篇】Django小项目简单BBS论坛部分内容知识点
开发一个简单的BBS论坛 项目需求: 整体参考“抽屉新热榜” + “虎嗅网” 实现不同论坛版块 帖子列表展示 帖子评论数.点赞数展示 在线用户展示 允许登录用户发贴.评论.点赞 允许上传文件 帖子可被 ...
- python 学习笔记二十 django项目bbs论坛
项目:开发一个简单的BBS论坛 需求: 整体参考“抽屉新热榜” + “虎嗅网” 实现不同论坛版块 帖子列表展示 帖子评论数.点赞数展示 在线用户展示 允许登录用户发贴.评论.点赞 允许上传文件 帖子可 ...
- http://bbs.ednchina.com/BLOG_345002072_2001308.HTM
http://bbs.ednchina.com/BLOG_345002072_2001308.HTM
- 客户访问站点将bbs/链接 跳转至forum/链接下的两种方式
显性 302 暂时重定向跳转 server { listen 80 ; server_name localhost; index index.html index.htm index.php; roo ...
- 前博客 http://bbs.landingbj.com/mytopic.jsp?action=mytopic&username=57071
在工作学习的过程中,遇到了亮眼的技术点,或者 学习的心得体会,总想要记录下来,或是方便自己,或是帮助如同自己现在这般的新人.前人种树,后人乘凉.享受了前人留下的阴凉,也会考虑自己给后来者种下几棵树苗. ...
- bbs树形打印(一)
前言:大家在bbs回帖时常常可以看到树形的回复形式. dfs设计 (1) 为使得Connection仅打开一次,因此以conn作为其中一个递归参数,在递归全程不关闭conn; (2)根据存入数据的树状 ...
- python小打小闹之简陋版BBS
闲的蛋疼,索性写个东西玩,于是,写个类似于BBS的念头就开始了. 我们考虑到需要实现的功能: 1 只有登陆的用户才可以点赞,如果没有登陆,那么不可以点赞,点赞次数只可以为1. 2 只有登陆的用户可以评 ...
- http://bbs.tianya.cn/post-stocks-1665898-1.shtml
http://bbs.tianya.cn/post-stocks-1295707-1.shtml 写过交易计划吗?有没有提前关注过某些板块或者某些股票呢?自选股里边有多少只股票?你平时复盘都是什么习惯 ...
- bbs网站 models
bbs网站 models #!/usr/bin/env python #_*_coding:utf-8_*_ from django.db import models from django.cont ...
- 中大bbs
发现个好像很好玩的东东, 中大bbs: luit -encoding gbk telnet bbs.sysu.edu.cn
随机推荐
- Android大学课件SQLite3 数据库操作
一.数据库介绍 SQLite3:当有大量相似结构的数据需要存储的时候 . 其实SQLite3 就是一个文件,类似之前学过的MySQL SqlServer等. 二.SQLiteOpenHelper 是一 ...
- 【BZOJ2333】【SCOI2011】棘手的操作 treap合并
题目大意 有\(n\)个节点,标号从1到\(n\),这\(n\)个节点一开始相互不连通.第\(i\)个节点的初始权值为\(a_i\),接下来有如下一些操作: \(U~x~y\):加一条边,连接第\(x ...
- 【XSY1519】彩灯节 DP 数学 第二类斯特林数
题目大意 有\(n\)盏灯,\(m\)个限制.每个限制\((x,y)\)表示第\(x\)盏灯与第\(y\)盏灯之间必须且只能亮一盏. 记一种情况\(x\)亮着的灯的数量为\(f_x\),求\( ...
- Google Apps的单点登录-谷歌使用的单点登录
简述: Customer :客户 Google:谷歌 Identity Provider:身份提供者安全断言标记语言(英语:Security Assertion Markup Language,简称S ...
- pytorch解决鸢尾花分类
半年前用numpy写了个鸢尾花分类200行..每一步计算都是手写的 python构建bp神经网络_鸢尾花分类 现在用pytorch简单写一遍,pytorch语法解释请看上一篇pytorch搭建简单网 ...
- HNOI2019总结
HNOI2019总结 Day 1 开场看三道题,T1是个计算几何,T2是个操作树加\(border\),T3题意有点复杂.想T1想了半个多小时,发现那个钝角不是很会处理,但是40分暴力应该还是可以写, ...
- CF868F Yet Another Minimization Problem 分治决策单调性优化DP
题意: 给定一个序列,你要将其分为k段,总的代价为每段的权值之和,求最小代价. 定义一段序列的权值为$\sum_{i = 1}^{n}{\binom{cnt_{i}}{2}}$,其中$cnt_{i}$ ...
- Java抽象类简单学习
使用抽象类应该注意的几个要点: 包含一个或者多个抽象方法的类必须被声明为抽象类. 将类声明为抽象类,不一定含有抽象方法. 通常认为,在抽象类中不应该包括具体方法,建议尽量将通用的域和方法放在超类中. ...
- 「HNOI2016」网络 解题报告
「HNOI2016」网络 我有一个绝妙的可持久化树套树思路,可惜的是,它的空间是\(n\log^2 n\)的... 注意到对一个询问,我们可以二分答案 然后统计经过这个点大于当前答案的路径条数,如果这 ...
- wampserver安装之后出现“无法启动,因为计算机中丢失了msvr110.dll”
1.是因为计算机缺失包所致,我的解决办法是安装一个包来解决. 2.网址如下:下载网址 3.下载完之后,然后安装就是(根据自己的系统版本来选择合适的安装版本).