一、基本要求
作业题目:开发BBS+BLOG系统
作业需求:
1 基于ajax和用户认证组件实现登录验证 2 基于ajax和form组件实现注册功能 3 系统首页文章列表的渲染 4 个人站点页面设计
5 文章详细页的继承
6 点赞与踩灭
7 评论功能
8 富文本编辑器的使用
9 防止xss攻击
评论处、上传文章处都要防止xss攻击--凡是向网站输入内容的都要防止
博客系统开发:
1.注册,登录,首页 2.个人站点,分组:(分类,标签,归档) 3.文章详细页 4.点赞,踩灭 5.评论楼,评论树 6.后台管理,发布文章,文件上传 7.BeautifulSoup 8.日志
----
演示内容,
1、注册输入为空,输入已注册过的信息提交
2、登录为空、输入错误提交
3、展示首页---注销--重新输入---
4、个人站点--展示--进入文章详情页
5、评论--点赞---防xss攻击评论
6、后台管理--先正常文字图片---在防xss攻击编辑
一、项目流程:
项目流程: 1 搞清楚需求(产品经理) (1) 基于用户认证组件和Ajax实现登录验证(图片验证码) (2) 基于forms组件和Ajax实现注册功能 (3) 设计系统首页(文章列表渲染) (4) 设计个人站点页面---跨表查询,分组查询 (5) 文章详情页 (6) 实现文章点赞功能 (7) 实现文章的评论 ---文章的评论 ---评论的评论 (8) 富文本编辑框 和 防止xss攻击(防止别人提交js代码) 2 设计表结构 3 按着每一个功能分别进行开发 4 功能测试 5 项目部署上线
二、功能实现
参考:
https://www.cnblogs.com/venicid/p/9446064.html
https://www.cnblogs.com/alice-bj/p/9160388.html
1、注册、登录、注销、出错页面
2) 注册 /register/ 3) 登录 /login/ /get_validCode/ # 验证码 4) 注销 /logout/ 5) 404页面 not_found.html
基于用户认证组件和Ajax实现登录验证(图片验证码)
基于forms组件和ajax实现注册功能
--------
引入Bootstrap <h3 class="text-primary text-center">注册页面</h3> <form> <div class="form-group "> <label for="username">username</label> <input type="text" class="form-control " placeholder="username" id="username"> </div> </form>
2、主页、个人站点,文章详情页
0) 主页 /index/
1) 个人站点页面(分类、标签、归档) /alex/ 2) 文章详情页(分类、标签、归档) /alex/articles/4 /digg # 点赞 /comment # 评论 /get_comment_tree # 评论树展示 4)media开放目录 /media
0 博客首页布局
登录状态和未登陆状态的两种区别
导航栏设计---Bootstrap--导航条
主页左右栏设计补充
知识点: 1.bootstrap搭建页面 2.导航条 登录: username / 注销 未登录: 登录 / 注册 3.for循环 {% for article in article_list %} {% endfor %}
1 个人站点
ORM跨表与分组查询
知识点: 1.文章列表,分类列表,标签列表,日期归档列表 文章列表: 分类列表: 标签列表: 日期归档列表: 2.模板继承 {% extends 'base.html' %} {% block content %} {% endblock content%}} 3.自定义标签 /blog/templatetags/my_tag.py @register.inclusion_tag('') def get_menu(username): ... return {} # 去渲染 4.分组查询 .annotate() / extra()应用 多表分组 tag_list = Tag.objects.filter(blog=blog).annotate( count = Count('article')).values_list('title', 'count') 单表分组 / DATE_FORMAT() / extra() date_list = Article.objects.filter(user=user).extra( select={"create_ym": "DATE_FORMAT(create_time,'%%Y-%%m')"}).values('create_ym').annotate( c = Count('nid')).values_list('create_ym', 'c') 5. 时间、区域配置 TIME_ZONE = 'Asia/Shanghai' USE_TZ = False
2、文章详情页的设计
知识点: 1.模板继承 article = Article.objects.filter(pk=article_id).first() {% extends 'base.html' %} {% block content %} ... {{ article.articledetail.content|safe }} {% endblock content %}
3、点赞、踩灭
----------------
知识点: 1.ajax的post var csrfmiddlewaretoken = $('input[name="csrfmiddlewaretoken"]').val(); 2.事务 try: # article_id 与 user_id 联合唯一 所有使用 try ... with transaction.atomic(): ArticleUpDown.objects.create(is_up=is_up, article_id=article_id, user_id=user_id) ... Article.objects.filter(pk=article_id).update(up_count=F('up_count')+1) except Exception as e: ... 3.F查询: Article.objects.filter(pk=article_id).update(up_count=F('up_count')+1)
4、评论楼、评论树
ajax显示评论
1.提交根评论 2.显示根评论 --- render显示 --- ajax显示 3.提交子评论 4.显示子评论 --- render显示 --- ajax显示 评论楼 评论树 1.ajax提交评论 post (csrfmiddlewaretoken) pid = "" 根评论 pid = value 子评论 2.回复事件 @alex val ="@" + $(this).attr('username')+ ' '; 3.事务 with transaction.atomic(): ... 多个orm sql操作! 4.F查询,更新 Article.objects.filter(pk=article_id).update(comment_count=F("comment_count")+1) 评论树: 5.js匿名函数 (function(){})() 6.ajax get方式获取comment_list $.each(comment_list,function(index,comment)){ ... s = '...' if(pid){ //子评论 $('#'+pid).append(s) }else{ //根评论 $('.comment_tree').append(s) } } 7.JsonResponse() 返回 non-dict objects 需要 safe=False def get_comment_tree(request, article_id): ret = list(Comment.objects.filter(article_id=article_id).values( 'pk', 'content', 'parent_comment_id', 'user__username').order_by('nid')) return JsonResponse(ret, safe=False)
5、后台管理、KindEditor、BeautifulSoup
/cn_backend # 主页 /cn_backend/add_article/ # 添加文章 /cn_backend/edit_article/4 # 编辑文章 /delete # 删除
知识点: 1.新建APP(backend) settings: INSTALLED_APPS = [..., 'backend.apps.BackendConfig',] 2.url分配 re_path(r'backend/', include(('backend.urls', 'backend'))), 3.认证装饰器 @login_required settings: LOGIN_URL = '/login/' 4.static配置 STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'blog', 'static'), os.path.join(BASE_DIR, 'backend', 'static'), ] 5.编辑器(KindEditor) <textarea name="article_con" id="article_box" cols="30" rows="10"></textarea> <script src="/static/kindeditor/kindeditor-all.js"></script> KindEditor.ready(function (k) { window.editor = k.create('#article_box', { ... ... uploadJson: 'upload_img/', extraFileUploadParams: {"csrfmiddlewaretoken":$('input[name="csrfmiddlewaretoken"]').val()}, filePostName: 'img' }) }) 6.文件上传 用户文件存在 /media/article_imgs/... media_path = settings.MEDIA_ROOT path = os.path.join(media_path, 'article_imgs', img_obj.name) 返回json img_obj = request.FILES.get('img') res = { "url": "/media/article_imgs/"+img_obj.name, "error": 0 } return HttpResponse(json.dumps(res)) 7.发布文章 防止XSS攻击 BeautifulSoup,对网页,解析数据 article_con = request.POST.get('article_con') soup = BeautifulSoup(article_con, 'html.parser') # 过滤script, 删除了所有的script标签 for tag in soup.find_all(): if tag.name == 'script': tag.decompose() # soup.prettify() == str(soup) return redirect(reverse('backend:index'))
三、所用技术概述
1、验证用户是否登录:用户认证组件 实质:session会话跟踪技术 from django.contrib import auth 通过中间件auth_middleware.py,采用白名单,对url进行控制,替代装饰器@login_requierd,否则每一个函数都有要加装饰器。 from django.utils.deprecation import MiddlewareMixin 2、验证字段:表单forms组件 对每个数据库中的字段进行校验,返回error from django import forms 3、自定义分页器 分页器pagination.py 解耦 from blog.utils.pagination import MyPaginator # 分页器 4、记录日志log settings配置文件,终端打印sql语句 mylog.py 日志文件,解耦,终端打印并在log文件记录用户操作 import logging 5、模板继承 {% extends 'base.html' %} {% block site-header %} {% endblock %} 6、ORM表关系 一对一(user blog) 一对多(user article) 多对多(article tag) 7、注意点: 1) 时区: settings.py配置 # TIME_ZONE = 'UTC' TIME_ZONE = 'Asia/Shanghai' USE_TZ = False 2) 静态文件目录 STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static') ] 8、连接mysql数据库 settings配置 # 连接mysql数据库 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'cnblog', # 要连接的数据库,连接前需要创建好 'USER': 'root', # 连接数据库的用户名 'PASSWORD': 'root', # 连接数据库的密码 'HOST': '127.0.0.1', # 连接主机,默认本级 'PORT': 3306, # 端口 默认3306 } } 9、评论后发送邮件 settings文件配置 # 发送邮件 EMAIL_USE_SSL = True # EMIAL_HOST = 'smtp.exmail.qq.com' # 如果是163 改成smtp.163.com EMAIL_HOST = 'smtp.qq.com' # 如果是 163 改成 smtp.163.com EMAIL_PORT = 465 EMAIL_HOST_USER = '719633333@qq.com' # 账号 EMAIL_HOST_PASSWORD = 'or333333ndzubdie' # qq邮箱的授权码而不是密码 DEFAULT_FROM_EMAIL = EMAIL_HOST_USER views视图 from django.core.mail import send_mail # 发送邮件 # 多进程发送邮件 t = threading.Thread(target=send_mail, args=("你的文章【%s】新增了一条评论内容" % article_obj.title, content, settings.EMAIL_HOST_USER, [request.user.email], )) t.start() 10、验证码 PIL模块生成验证码 from PIL import Image, ImageDraw, ImageFont 11、自定义tag标签 from django import template register = template.Library() @register.inclusion_tag("blog/classification.html") def get_classification_style(username): 12、数据库事务操作 from django.db import transaction # 事务操作 13、富文本编辑框 KindEditor 14、防止xss攻击 from bs4 import BeautifulSoup
其他
xss攻击
{{ article_obj.content|safe }} safe是让所用提交都通过
我们在提交阶段认为的剔除非法的标签
标签页的知识:
data-toggle="tab"——指明标签项具有切换响应功能; .tab-content——包裹标签页的所有内容部分; .tab-pane——包裹对应标签项的内容部分; .fade——设置标签项切换时有淡入淡出的效果; .in——设置标签页第一项淡入的初始化效果; .active——设置标签页以及对应标签项的内容处于激活状态;
----
<!-- Nav tabs Bootstrap 中的--选项卡--> <ul class="nav nav-tabs" role="tablist"> <li role="presentation" class="active"><a href="#home" aria-controls="home" role="tab" data-toggle="tab">文章</a></li> <li role="presentation"><a href="#profile" aria-controls="profile" role="tab" data-toggle="tab">日记</a></li> <li role="presentation"><a href="#messages" aria-controls="messages" role="tab" data-toggle="tab">随笔</a> </li> <li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">相册</a> </li> </ul> <!-- Tab panes --> <div class="tab-content"> <div role="tabpanel" class="tab-pane active" id="home"> {% block content %} {% endblock %} </div> <div role="tabpanel" class="tab-pane" id="profile"> <img src="/static/img/meinv2.jpg" alt=""> <img src="/static/img/meinv3.jpg" alt=""> <img class="pull-right" src="/static/img/meinv.jpg" alt=""> </div> <div role="tabpanel" class="tab-pane" id="messages"> <img width="180" height="180" src="/static/img/hashiqi2.jpg" alt=""> <img width="180" height="180" src="/static/img/dogg4.jpg" alt=""> <img width="180" height="180" src="/static/img/linhaifeng.jpg" alt=""><br> <img width="180" height="180" src="/static/img/dogg3.jpeg" alt=""> <img width="180" height="180" src="/static/img/dogge2.jpg" alt=""> <img width="180" height="180" src="/static/img/dogg5.jpg" alt=""> </div> <div role="tabpanel" class="tab-pane" id="settings"> </div>
防止xxs攻击
<script>alert(1111)</script>
数据库(pycharm连接mysql数据库) models.py 注册 /reg/ 上传头像 request.FILES.get('avatar') 登录 /login/ 随机验证码 /get_valid_img/ 首页 /index/ 个人站点 分类,标签,归档 /blog/egon/ 文章详细页 /blog/egon/articles/2/ 点赞,踩灭 /blog/poll/ ajax的post 事务 评论楼,评论树 /blog/comment/ 根评论,子评论 render显示,ajax显示 后台管理,发布文章 /backend/index/ 新建APP 认证装饰器 编辑器(KindEditor) 文件上传 /media/article_imgs/... 防止XSS攻击 BeautifulSoup