web开发-Django博客系统
项目完整流程
项目流程: 1 搞清楚需求(产品经理) (1) 基于用户认证组件和Ajax实现登录验证(图片验证码) (2) 基于forms组件和Ajax实现注册功能 (3) 设计系统首页(文章列表渲染) (4) 设计个人站点页面 主要是orm查询 (5) 文章详情页 (6) 实现文章点赞功能 (7) 实现文章的评论 ---文章的评论 ---评论的评论 (8) 富文本编辑框和防止xss攻击
(9) 密码修改
2 设计表结构
用户信息表
个人站点表
个人文章分类表
文章标签
文章表
点赞表
评论表
文章和标签多对多关系表 3 按着每一个功能分别进行开发 4 功能测试 5 项目部署上线
一、创建项目和数据迁移
步骤
1、因为user_info表继承了Django的user,需要在setting里面加入AUTH_USER_MODEL=‘blog.user_info’
2、设置数据库
3、开始数据迁移
相关命令
数据库
管理员运行cmd
net start mysql
创建数据库
create database blog;
python
python manage.py makemigrations
python manage.py migrate
二、登陆功能
基于用户认证组件和Ajax实现登录验证(图片验证码)
要点总结:
1、利用PIL模块生成验证码图片
2、利用IO模块调用内存空间,提高验证码图片的生成和获取效率
3、保存当前验证码,存入session
4、刷新验证码,在请求链接末尾加?,即刷新
创建超级用户命令,以便于操作
python36 manage.py createsuperuser
优化代码和用户体验
1、清空上次错误信息,
2、解耦验证码函数,单独创建工具包utils,放置获取验证码函数
提高要求,插入滑动验证码
利用SDK模块 www.geetest.com 极验滑动验证码官网
需要social-auth-app-django模块配合
三、注册功能
基于forms的注册页面
1、创建myforms组件
2、forms组件渲染注册页面,auto_id,头像另外添加
4、默认头像设置,点击头像打开选择图片框(即点击input)隐藏input框
5--头像预览:
1 获取用户选中的文件对象 $()[0].files[0]change事件
2 获取文件对象的路径 new FileReader()
3 修改img的src属性 ,src=文件对象的路径怎么设置头像选择路径?render异步---所以要这样处理(reader.onload=function(){ 显示图像的代码 })
Ajax发送注册信息
1、按钮点击事件
2、需要传输文件对象,要用new FormData
3、优化formData的数据sarializeArray 提取form表单的数据,整理成一个数组
4、显示错误信息,$.each循环错误msg,1先清空,2错误的变成红色框
5、错误信息改为中文
6、局部钩子和全局钩子
7、__all__的错误信息的处理
error_messages 的字段大全?
8、数据校验通过后,1模板中,直接location跳转、2、在视图中,生成用户记录,
9、filefield字段和imagefield字段
media配置
1、关于对静态文件的区分
/static/ JS css img
/media/ 用户上传的文件
2、media配置
使用media的好处----
默认头像路径如果是空的判断,设置成默认头像
3、media_url配置
浏览器如何能直接访问到media中的数据
settings.py:
MEDIA_URL="/media/"
urls.py:from django.views.static import serve
# media配置:
re_path(r"media/(?P<path>.*)$",serve,{"document_root":settings.MEDIA_ROOT})
注册用户代码优化
去除重复代码逻辑
利用extar={}传入头像值
四、系统首页
页面设计
头部导航
登陆之后显示用户名
添加登陆头像
主页文章的渲染
admin的使用,
admin(不是必需的):
Django内部的一个组件:后台数据管理组件(web页面)超级用户登陆才能使用python manage.py createsuperuser 针对用户认证组件对应的用户表admin注册:在app下的admin.py中
admin.site.register(models.UserInfo)录入文章
注意:在用户注册后,就应该生成相应的站点博客,需要一个页面来注册博客站点
遗留:没有设置账户登陆有效时间
渲染
1、从数据库去除数据
2、标题,直接取出title
头像,文章对应的user的avatar ,路径前加上media,限制图片大小
摘要,直接取出desc,bootstrap用法 media-left 和media-right
发布信息,发布者  : 发布时间(修改时区)  ;评论;点赞 设置样式
提醒:样式文件依然不能完全加载,把文件内容复制到了另一个文件中,重新引入,才生效了
原因:浏览器首先会加载之前吓到到本地的缓存,如果修改的样式文件没有生效,要首先去浏览器的设置---->高级---->清除浏览数据---->清除数据
体会:感觉数据库存储,前端的搭配,Django的渲染,是如此的美妙,
五、个人站点页面
1,个人站点url,视图
2、判断是否存在user,用来跳转到用户站点
3、orm查询,跨表和分组查询
分类
标签
日期
注意:Django数据查询好渣,要练
日期的分组查询 extra 和date_format 和 TruncMonth
4、渲染
5、过滤跳转
路由设置有名分组,
模板根据分组设置路径
视图从路径得到的分组名, 查询数据库数据
渲染到主页
六、文章详情页
代码优化,函数复用,模板继承,模板能直接接受字典数据context
templatetags自定义标签
register.inclusion_tag 样式和数据结合成一个整体
文章的渲染
文章字符串转义(排版)
safe
xss攻击
七、点赞
绑定事件,通过判断类名获得布尔值
ajax发送的后台
去除文章ID、布尔值、在request.user.pk 中得到登陆用户,即点赞者的id
添加到点赞记录表中
在文章表中同步点赞或者反对值,用到 F查询自加
根据返回状态,前端显示提示消息
点赞代码优化
八、评论
根评论:对文章的评论 子评论:对评论的评论 111 444 555 222 333 Comment nid user_id article_id content parent_comment_id(null=True) 1 1 1 111 null 2 2 1 222 null 3 3 1 333 null 4 4 1 444 1 5 5 1 555 4
实现流程
60、搭建样式
61、填写评论--->ajax事件提交到后端---->提取---->创建到数据库---->清空评论框
62、显示评论 ---render显示---->提取数据对象--->文章详情页的视图中提取----->渲染样式forloop.counter计数显示楼层
63、显示评论---ajax显示---->提交后,视图中提取,并返回--->从响应返回值里面拿数据----> 视图中提取创建时间(格式化)、评论内容、评论人、--->建立字符串标签(要用ex6语法,不用加号)---->添加到ul中
64、回复按钮事件---获取焦点---赋文本值(@此评论的评论者)
65、提交子评论---pid赋值---自定义属性值(此评论的ID)--->处理content(换行符,切片)----重置pid
66、render显示子评论---
67、ajax显示子评论----
68、评论树---递归,效率低----- >新方式----->
74、事务操作,模块transaction
75、发送邮件----模块------优化速度---开线程
九、后台管理
76、后台设计----文版编辑器kindediditor---文件上传----uploadJson----extraFileUploadParams(带cs_token参数)---filePostName (指定传输的文件名字)---下载到本地服务器---视图返回路径,放在编辑器里
80、文章摘要的保存
---1、列表截取----->2、有样式之后,乱套---截取纯文本才可以---3、bs4—beautifulSoup------4、获取文本
---5、防御xss攻击---过滤标签
十、修改密码
利用auth模块的user对象的方法check_password验证密码,set_password修改密码
十一、要点记录(按照文件目录的顺序)
1、templates下的mytags--->自定义标签
# inclustion_tag中引入模板,将数据和模板绑定在了一起
效果:左侧和顶部样式和个人站点一样,使用模板继承,自定义标签来复用代码,并且使样式和数据一体
2、获取随机验证码
1、相关模块
from PIL import Image, ImageDraw, ImageFont 生成图片和在图片上添加文字,噪点噪线
from io import BytesIO 调用内存空间
import random
2、生成的验证码保存在session中,防止各个浏览器用户冲突
request.session['valid_code_str'] = valid_code_str
3、模型层
1、定义用户表,给系统自带的auth表添加自己的字段
相关模块from django.contrib.auth.models import AbstractUser 需要继承这个类
2、打印真个对象时,显示标题名,可自定义
def __str__(self):
return self.title
3、联合唯一
class Meta:
unique_together = [
('article', 'tag'),
]
4、forms组件
1、检验字段
2、钩子
cleaned_data 校验完的数据
__all__全局错误名
全局钩子
局部钩子
3、相关模块
from django.forms import widgets 添加渲染到class
from django.core.exceptions import ValidationError 用来生成 提示错误
5、分页器
1、from django.core.paginator import Paginator
2、获取要处理的列表--->生成分页器对象--->当前页码--->当前页--->页码列表
返回调用者,当前页和页码列表
3、根据请求页码,会有不同的页码列表展示逻辑,以确保页码不会超宽导致页码编程两行
确保不会出现负数的逻辑
6、路由层的设置
path
re_path
处理需要匹配的格式
^ $ |
有名分组
<int:name>
(?P<name>)
有的路由会会被覆盖的问题
放在上面,防止被覆盖
7、视图函数
1、插入数据还是用的笨方法
文本获取字符串,然后切割
2、主要模块
from django.shortcuts import render, HttpResponse, redirect
from django.http import JsonResponse 直接json返回内容
from django.contrib import auth
from django.db.models import Count, F, Sum 数据库方法
from django.db.models.functions import TruncMonth 时间达到月份
from django.db import transaction 事务操作
from django.core.mail import send_mail 发送邮件
from django.contrib.auth.decorators import login_required
from bs4 import BeautifulSoup 过滤非法标签
import json
import os
import random
from threading import Thread 线程用于发送邮件,提高程序速度
3、添加新文章
1、ajax发送数组
前端定traditional:True
后台:array = request.POST.getlist('ids') #django接收数组
2、bs4用来获取html的文本内容
过滤非法字符串
3、kinded编辑器发送图片文件
4、获取编辑器内容
同步编辑器和标签
html = editor.html();
editor.sync();
editor.html()
5、图片上传
前端
uploadJson:'/upload/' 设置上传路由
filePostName:'up_load_img' 文件的别名
后端
视图函数
获取到对象--img = request.FILES.get('up_load_img')
保存
返回方式,错误和保存在服务器的
response = {
'error': 0,
'url': '/media/add_article_img/%s' % img.name
}
return JsonResponse(response)
4、评论
1、事务,因为涉及到多个表
2、发送邮件到作者邮箱
多线程处理邮件发送,不影响前端体验
setting的设置
邮件服务器,授权码
3、返回本条消息内容到浏览器,浏览器添加本条评论到页面
因为插入数据库后返回就是数据库对象,可以直接获取其中的字段,用来返回
4、前端评论树样式
1、每条消息设置一条虚线背景图片
2、子评论单独添加一张透明的图片定位在左上角,只要下面的虚线边框
3、调整位置,使其像一个树结构
4、还不够完整,多出了虚线还没有处理
核心:
子评论利用有父评论ID,找到父级,添加在父级之后
再利用css,magin-left得到基本评论树的框架
5、没有评论逻辑判断
5、点赞和踩灭
true 是赞 False 是踩
1、登陆者即是点赞人
不能操作自己文章的逻辑,判断是不是自己的文章,返回状态
判断记录表中是否有该用户对该文章的操作
2、事务操作
3、判断是点在还是踩灭
前端html中
核心--取值判断是否有digg(赞图标所在的标签)类,得到布尔值
取值时用了json--->is_up = json.loads(request.POST.get('is_up'))
4、前端数字的自加
5、若是不能操作
返回is_up,和失败标志,前端根据is_up,显示相应的消息
var val=data.handle? '您已经推荐过了': '您已经反对过了';
6、个人站点
1、使用自定义标签
2、复用函数,返回字典--->得到返回字典·以context字典传入数据,-->前端直接调用key
3、路由匹配,查询文章分类,标签,以及归档日期
re_path(r'^(?P<username>\w+)/(?P<conditon>tag|category|archive)/(?P<param>.*)/$', views.home_site),
7、注销
用户认证模块auth.logout(request)
8、注册
1、forms组件
2、头像
取头像在FILES中avatar_obj = request.FILES.get('avator')
当用户没有传头像的判断
extra,若取到了,加到这个字典中,插入时用extra
前端头像预览
获取头像路径,覆盖原头像
reader=new FileReader()
reader.readAsDataURL(file_obj);
// 修改img的src的属性,覆盖原图片
reader.onload=function () {
$('#avator_img').attr('src',reader.result)
};
3、提交注册数据
需要 form_data=new FormData();然后append
var requset_data=$('#form').serializeArray();
$.each(requset_data,function (index,data) {
form_data.append(data.name,data.value)
// 编码类型两个参数
contentType:false,
processData:false,
4、全局错误的展示
9、登陆
auth模块
从session中取出验证码与前端对比
user = auth.authenticate(username=user, password=pwd)
注册session
auth.login(requset, user)
8、media文件夹
settings的设定
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
路由设置
作用:放置用户上传的媒体文件,头像等
9、settings
1、添加APP
2、配置数据库信息
3、时区的设置
4、USE_TZ设置成False
5、static
6、media
7、邮箱配置
8、session的过期时间
10、路由补充
include 路由分支
在路由中注册media
** re_path(r"media/(?P<path>.*)$",serve,{"document_root":settings.MEDIA_ROOT})
11、static
静态文件分开单独放
12、templates,模板层
base模板继承
include引用模板
13、其他
多选下拉框组件
引入css和js
class加入selectpicker
多选multiple
输入框标题title="--请选择"
取值,和普通标签相同
刷新option,$('.selectpicker').selectpicker('refresh');
14、css和js
弹出模态框bootstrap
添加cstoken,才能通过post发送ajax数据
csrfmiddlewaretoken:$('[name=csrfmiddlewaretoken]').val()
form使用form-group、form-control
时间格式的处理
<td>{{ article.create_time|date:'Y-m-d H:i' }}</td>
文档的安全safe
15、文本编辑器
引入
参数配置
文件上传
同步数据到输入框
获取数据
赋值