1.项目开发基本流程

1.需求分析
2.架构设计
3.分组开发
4.提交测试
5.交付上线

2.项目流程

仿造博客园项目(核心:文章的增删改查)
1.表分析:
1.1用户表
1.2个人站点表
1.3文章表
1.4文章标签表
1.5文章标签表
1.6点赞点踩表
1.7文章评论表 2.基础字段分析
'''下列表字段仅供参考,可以扩展'''
2.1用户表:替换auth_user表并扩展字段:电话号码、头像、注册时间
2.2个人站点表:
站点名称
站点标题 站点样式(css文件)
2.3文章表
文章标题
文章简介
文章内容
发布时间
2.4文章分类表
分类名称
2.5文章标签表
标签名称
2.6点赞点踩表:记录哪个用户给哪篇文章点了推荐(赞)还是反对(踩)
用户字段(用户主键)>>>:外键字段
文章字段(文章主键)>>>:外键字段
点赞点踩
2.7文章评论表:记录哪个用户给哪篇文章评论了什么内容
用户字段(用户主键)>>>:外键字段
文章字段(文章主键)>>>:外键字段
评论内容
评论时间
外键字段(自关联)
"""
评论有两种情况:
1.针对文章的评论,叫做根评论。
2.针对某条评论的评论(或回复),叫做子评论。
""" 3.外键字段
3.1用户表:用户表和个人站点是一对一外键关系。
3.2个人站点表:暂无外键
3.3文章表:
文章表和个人站点表是一对多关系
文章表和文章分类表是一对多外键关系
文章表与文章标签表 是多 对多关系
文章评论数
文章点赞数
文章点踩数
"""
我们本想通过跨表查询拿到文章的评论数、点赞数,但是文章需要频繁的展示,每次跨表查询效率极低,所以我们在文章表中再创建三个普通字段:评论数,点赞数,点踩数。之后只需要确保每次操作评论表或者点赞点踩表时同步修改上述三个普通字段即可。
"""
3.4文章分类表:文章分类与个人站点是一对多外键关系
3.5文章标签表:文章标签与个人站点是一对多外键关系

3.表创建(包含数据库迁移命令)

1.由于views中用来存放视图函数,我们将form组件的校验内容放在应用当中新建一个py文件。

2.针对多对多字段(文章表和标签表)采用半自动创建第三张表方式。手动创建的第三张表需要指定和哪张表关联(),并且多对多关系中外键所在的一方需要指明通过哪张表(第三张表)以及哪些字段和另一张表连接。
eg:
tags = models.ManyToManyField(to='Tag',through='Article2Tag',through_fields=('article','tag'),null=True)

4.注册功能

1.选择头像时选择照片选完就出现在图片链接上:
<label for="myfile">头像 # 和input按钮id一样,点击头像和点击input按钮效果一样
<img src="/media/avatar/default.png" alt="" width="50" id="myimg">
</label>
<input type="file" id="myfile" style="display: none"> <script>
// 用户头像实时展示:固定以下代码
$('#myfile').change(function () {
let myFileReadObj = new FileReader();
let fileObj = this.files[0];
myFileReadObj.readAsDataURL(fileObj);
myFileReadObj.onload = function () {
$('#myimg').attr('src',myFileReadObj.result)
}
})
</script> 2.用ajax传输数据:
"""
用ajax提交数据时,form表单的input标签的type不能为submit,因为submit会触发form表单的提交功能,和ajax冲突。
"""
console.log(标签选择器.serializeArray())可以拿到一个数组套对象(列表套字典)
<script>
// 给注册按钮绑定点击事件,发送ajax请求,携带文件数据
$('#subBtn').click(function () {
let myFormDataObj = new FormData();
console.log($('#form').serializeArray())
})
</script>
# [{},{},{},{}]

我们将拿到的结果$('#form').serializeArray()进行for循环,发现a是索引值,b是对象(字典)。
<script>
$('#subBtn').click(function () {
let myFormDataObj = new FormData();
$.each($('#form').serializeArray(),function (a,b) {
console.log(a,b)
})
})
</script>
'''
0 {name: 'username', value: 'max'}
1 {name: 'password', value: '222'}
2 {name: 'confirm_password', value: '222'}
3 {name: 'email', value: '275712541@qq.com'}
'''

"""
ajax携带数据的模板:
<script>
$('#d3').click(function () {
// 1.先产生一个FormData对象
let myFormDataObj = new FormData();
// 2.往该对象中添加普通数据
myFormDataObj.append('name', 'jason');
myFormDataObj.append('age', 18);
// 3.往该对象中添加文件数据
myFormDataObj.append('file', $('#d2')[0].files[0])
// 4.发送ajax请求
$.ajax({
url:'',
type:'post',
data:myFormDataObj, // ajax发送文件固定的两个配置
contentType:false,
processData:false,
success:function (args){
alert(args)
} })
})
</script>
"""
我们用对象分别点name和value就是拿到对象的键和至,传给myFormDataObj对象。但是该方法只能拿到普通字段,不能添加文件字段。
<script>
$('#subBtn').click(function () {
let myFormDataObj = new FormData();
$.each($('#form').serializeArray(),function (index,dataObj) {
myFormDataObj.append(dataObj.name,dataObj.value)
})
})
</script> 3.成功传输数据后,在后端去掉confirm键值对(因为如果能传到后端说明password和confirm_password一样),然后再添加一个键值对:avatar,值是文件对象。然后用**将字典打散成关键字参数传入。 4.接下来我们要补充错误信息:生成一个字典。在前端根据结果不同显示不同结果。
success:function (args) {
if(args.code === 10000) {
window.location.href = args.url
}else{
console.log(args.msg)
}
}
args.msg是错误信息。我们先打印出来看看是什么效果:

结果是一个对象,对象的值是数组(错误信息),对象的键是字段名。
因为input标签在for循环你当中由form组件自动生成,所以我们没有办法直接拿到它的id,通过查看我们得知for循环中的input标签的id值是id_字段名。
# 4
所以我们采用拼接的方式拿到input标签的id值,在通过next拿到渲染错误信息的span标签,将错误信息渲染上去。
$('#subBtn').click(function () {
let myFormDataObj = new FormData();
$.each($('#form').serializeArray(),function (index,dataObj) {
myFormDataObj.append(dataObj.name,dataObj.value)
})
myFormDataObj.append('avatar',$('#myfile')[0].files[0])
$.ajax({
url:'',
type:'post',
{#'csrfmiddlewaretoken':{{ csrf_token }},#}
data:myFormDataObj,
contentType:false,
processData:false,
success:function (args) {
if(args.code === 10000) {
window.location.href = args.url
}else{
{#console.log(args.msg)#}
let dataObj = args.msg
$.each(dataObj,function (k,msgArray) { // k 是对象的键,msgArray是错误信息数组
let eleId = '#id_' + k
$(eleId).next().text(msgArray[0])
})
}
}
})
})
# 5 5.后端的if avatar_obj不能省略:
if avatar_obj: # 判断不能不加,如果不加用户不上传avatar_obj对应的值是None,不是默认头像。默认值只有不上传的时候才能使用
clean_data['avatar'] = avatar_obj

5.登录功能

1.img标签的src属性
1.可以直接填写图片地址
2.还可以填写一个路由 会自动朝该路由发送get请求
如果结果是图片的二进制数据 那么自动渲染图片 2.登陆验证码视频:
from PIL import Image, ImageFont, ImageDraw
from io import BytesIO, StringIO 随机产生三个数字,产生背景色:
def get_random():
return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255) def get_code_func(request):
img_obj = Image.new('RGB', (350, 35), get_random())
draw_obj = ImageDraw.Draw(img_obj)
font_obj = ImageFont.truetype('static/font/333.ttf', 25)
'''ttf字体下载网站:https://www.fonts.net.cn/font-20768396126.html'''
code = ''
for i in range(4):
random_upper = chr(random.randint(65, 90))
random_lower = chr(random.randint(97, 122))
random_int = str(random.randint(0, 9))
tem_choice = random.choice([random_upper, random_lower, random_int])
draw_obj.text((i * 60 +65, 0), tem_choice, font=font_obj)
code += tem_choice
print(code)
request.session['code'] = code
io_obj = BytesIO()
img_obj.save(io_obj, 'png')
return HttpResponse(io_obj.getvalue()) 点击验证码动态刷新:
<script>
// 验证码动态刷新
$('#d1').click(function () {
let oldSrc = $(this).attr('src');
$(this).attr('src',oldSrc + '?')
})
</script>
"""
每局部刷新一次验证码img标签的src属性后面的路由都会加一个问号,所以我们每点击一次图片验证码在路由后面加一个?
"""
# 1

6.修改密码

1.修改密码在前端用一个模态框来提示用户输入信息。模态框的触发器是一个a标签,需要在a标签中填写以下参数:data-toggle="modal" data-target="#myModal"才可以正常触发模态框弹出(myModal是模态框的id)。
要注意的是这个a标签作用是触发模态框,在模态框中点击提交按钮提交post请求,所以a标签不能再填写路由,因为填写路由代表向路由发送get请求,如果get请求没有提交Httpresponse对象后端会报错。

7.home页面搭建

1.前端页面在搭建头像时要注意userinfo和site的绑定。首先拿到所有文章的queryset,传到前端。

2.前端循环拿到所有的文章标题,文章简介。

3.在搭建头像和文章简介时,头像和文章在同一行,头像和文章简介分别用div包起来,头像的class为media-left,文章简介的class为media-body。
# 2 3

6.通过admin后台管理录入数据

1.首先注册超级管理员,然后登陆/admin/。

2.然后在应用下的admin.py中依次注册所有的表,这样我们可以通过admin后台管理录入数据:
from app01 import models
admin.site.register(models.表名) 3.修改user表名:
在models中表中添加添加以下代码:
class Meta:
verbose_name_plural = '用户表'
修改其他表表名:在类中添加__str__方法:
def __str__(self):
return f'{self.name}'
"""
超级管理员:jack 222222
普通用户:
max 222222
jason 222222
jerry 222222
""" 4.当我绑定用户表中的站点(外键Site)时,网页提示我们需要输入电话号码,我们只需要在models.py中的用户表字段phone后面添加blank=True即可,该字段指在后台管理录入数据时可以不上传该数据,不需要执行数据库迁移命令。 5.暴露文件目录:我们之前的用户头像文件都是直接存储在avatar目录中的,但是这个目录无法直接暴露在页面上,也就是我们的页面上无法直接显示用户的头像。因此我们需要在应用下新建一个media目录,并且在settings中声明MEDIA_ROOT = os.path.join(BASE_DIR, 'media')。
此外还需要在urls.py中新增一个路由:
from django.views.static import serve
re_path('media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT})。
由于此时我们的路径是app01>>>media>>>avatar>>>图片文件,所以我们还需要在前端代码拼接路径:
<img class="media-object" src="/media/{{ article_obj.site.userinfo.avatar }}" alt="" width="40">。
这样我们在网页上输入图片的路径也可以找到该文件。 6.不要忘记绑定用户表和个人站点表之间的关系。

6.个人站点功能

1.如果想模仿出博客园一样的效果,每个月发布了几篇文章,需要导入一个模块并且进行以下操作:
views.py: from django.db.models.functions import TruncMonth
def site_func(request, username):
site_obj = models.Site.objects.filter(site_name=username).first()
if not site_obj:
return render(request, 'errorPage.html')
article_queryset = models.Article.objects.filter(site=site_obj)
catagory_queryset = models.Category.objects.filter(site=site_obj).annotate(article_num=Count('article__pk')).values(
'name', 'article_num')
tag_queryset = models.Tag.objects.filter(site=site_obj).annotate(article_num=Count('article__pk')).values('name','article_num')
date_queryset = models.Article.objects.filter(site=site_obj).annotate(month=TruncMonth('create_time')).values('month').annotate(article_num=Count('pk')).values('month','article_num')
"""
前一个annotate作用是处理字段,后一个才是分组
"""
print(date_queryset) # <QuerySet [{'month': datetime.datetime(2023, 1, 1, 0, 0), 'article_num': 4}]> return render(request, 'sitePage.html', locals()) 2.如果报错提示为time zone相关内容则需要在settings.py中修改时区:
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = False 3.如果按照筛选功能输入指定年月的路由任然无法筛选文章那么在settings.py中设置(解决方式和上述问题一致):
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = False

7.侧边栏筛选功能

1.研究博客园三种情况下的筛选特性:
思路:在个人站点中再次筛选一些文章显示在页面上
分类筛选路由特性: 站点名称/catagory/数据主键值
标签筛选特性: 站点名称/tag/数据主键值
日期筛选特性: 站点名称/archive/文章

8.文章详情表

1.文章内容数据添加:如果想要复制别人的博客,只需要在别人的博客页面上右键>>>检查>>>点击cnblog_post_body>>>copy>>>copy outerHTML,然后在admin后台管理文章内容处粘贴以上代码。此外还需要在前端装上过滤器:
{{ article_obj.content|safe }}才能正常转译内容。

9.点赞点踩

1.后端判断逻辑:首先判断是否是POST请求,然后判断用户是否已经登陆,然后判断文章作者是否是已登录用户,在判断该用户表是否给该文章点过赞(或踩),再判断是赞还是踩,根据不同的结果在表中添加不同的数据。

2.添加点赞点踩图标:复制博客园的图标代码,css样式需要同步复制。
"""
模板的继承不仅需要继承body标签中的内容区域,还需继承每个标签(包含其子标签的js样式)(在head标签中的style标签中)。
<head>
{% block css %} {% endblock %}
</head> <body>
<script>
{% block js %} {% endblock %}
</script>
</body>
""" 3.当我们把点赞点踩图标成功显示在页面上时,在它的下面继续写内容,发现内容和图标在同一水平线上,这是因为浮动现象。我们需要用一个div标签将图标包起来,并且该div需要用class="clearfix"来取消浮动。 4.如何判断赞和踩:我们在后端发现赞和踩分别属于两个不同的class,所以我们在前端通过:
let isUp = $(this).hacClass('点赞独有的class'),拿到的isUp是一个js的布尔值('true'或'flase'),通过结果不同可以分辨是点赞还是点踩。 5.将isUp传到后端后,可以通过反序列化将js的布尔值转成python的布尔值:
up_or_down = request.POST.get('isup')
up_or_down = json.loads(up_or_down) 6.数据确认无误后,不但要在comment中添加数据,还要在article表中同步更新点赞数,采用F查询拿到指定字段中的数据后添加。 7.在传到前端的字典中的值如果是字符串,并且该字符串内含有前端代码,在前端渲染时用html(args.msg)。

文章评论

文章评论分为两部分:
1.评论样式搭建
2.评论楼渲染
1.评论样式搭建:
1.1前端的评论样式在文章详情表中搭建,首先判断用户是否已经登陆,如果登陆把评论框样式显示在页面上,如果未登录显示两个a标签:登录和注册。 1.2首先在全局定义一个全局变量parentIId,该全局变量用来记录是评论还是回复,默认为null(该全局变量和函数中类似,在每个点击事件中可以改全局变量)。给提交评论按钮绑定点击事件,同时将parentId发送到后端。 1.3给回复按钮绑定点击事件,在该点击事件中改parentId。
"""
默认点击回复按钮会自动跳到页首,如果想点击回复按钮定位到textarea标签,需要将回复的a标签定位到textarea标签,在a标签中修改:href="#textarea标签的id"。
"""

文章添加

1.Kindeditor富文本编辑器使用:http://kindeditor.net/docs/usage.html
Kindeditor富文本编辑器下载:http://kindeditor.net/down.php
下载好之后将文件拷贝一份到static目录下。 2.使用:
需要在添加文本框的html文件内加入以下代码:
<script charset="utf-8" src="/static/kindeditor/kindeditor-all-min.js"></script>
<script charset="utf-8" src="/static/kindeditor/lang/zh-CN.js"></script>
<script>
KindEditor.ready(function (K) {
window.editor = K.create('#mycontent',
{
width:'100%',
height:'300px',
resizeType:'0',
}
);
});
</script> """
mycontent是textarea的id值。宽度可以写百分比和长度(单位为px),高度只能写长度(px)。resizeType参数:2或1或0,2时可以拖动改变宽度和高度,1时只能改变高度,0时不能拖动。
"""

bbs大作业的更多相关文章

  1. 数据库大作业--由python+flask

    这个是项目一来是数据库大作业,另一方面也算是再对falsk和python熟悉下,好久不用会忘很快. 界面相比上一个项目好看很多,不过因为时间紧加上只有我一个人写,所以有很多地方逻辑写的比较繁琐,如果是 ...

  2. 程设大作业xjb写——魔方复原

    鸽了那么久总算期中过[爆]去[炸]了...该是时候写写大作业了 [总不能丢给他们不会写的来做吧 一.三阶魔方的几个基本定义 ↑就像这样,可以定义面的称呼:上U下D左L右R前F后B UD之间的叫E,LR ...

  3. 大作业NABC分析结果

    大作业NABC分析结果 这次的大作业计划制作一款关于七巧板的游戏软件.关于编写的APP的NABC需求分析: N:需求 ,本款软件主要面向一些在校的大学生,他们在校空闲时间比较多,而且热衷于一些益智类游 ...

  4. [留念贴] C#开发技术期末大作业——星月之痕

    明天就要去上海大学参加 2015赛季 ACM/ICPC最后一场比赛 —— EC-Final,在这之前,顺利地把期末大作业赶出来了. 在这种期末大作业10个人里面有9个是从网上下载的国内计算机水平五六流 ...

  5. Hadoop综合大作业

    Hadoop综合大作业 要求: 用Hive对爬虫大作业产生的文本文件(或者英文词频统计下载的英文长篇小说)词频统计. 用Hive对爬虫大作业产生的csv文件进行数据分析 1. 用Hive对爬虫大作业产 ...

  6. 爬虫综合大作业——网易云音乐爬虫 & 数据可视化分析

    作业要求来自于https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/3075 爬虫综合大作业 选择一个热点或者你感兴趣的主题. 选择爬取的对象 ...

  7. 期末Java Web大作业----简易的学生管理系统

    学生信息管理系统(大作业) 2018-12-21:此文章已在我的网站更新,添加视图介绍等信息,源码请移步下载https://www.jeson.xin/javaweb-sims.html PS:首先不 ...

  8. CSAPP HITICS 大作业 hello's P2P by zsz

    摘 要 摘要是论文内容的高度概括,应具有独立性和自含性,即不阅读论文的全文,就能获得必要的信息.摘要应包括本论文的目的.主要内容.方法.成果及其理论与实际意义.摘要中不宜使用公式.结构式.图表和非公知 ...

  9. #006 C语言大作业学生管理系统第三天

    还差最后两部分 读取文件 恢复删除的学生信息 先学会处理文件的 知识点,再继续跟着视频做这个作业. 应该明天周六能把视频里手把手教的学生管理系统敲完 第二周尽量自己能完成C语言课本最后面那道学生管理系 ...

  10. 最课程阶段大作业之01:使用SVN实现版本控制

    版本控制在友军那里都是放在整个培训的最后阶段才开始讲的,但我们打算放到SE阶段.与其匆匆在项目实战阶段弄个半生不熟,然后进入实际工作中接受他人对你的怀疑,不如……早死早超生~~~. 可是,我们毕竟现在 ...

随机推荐

  1. C#使用附加到进程调试

    微软官网的调试进程介绍 首先运行bin下的可执行文件,然后打开源代码,选择调试--->附加到进程.

  2. Linux C++目标中添加git版本信息

    项目代码根目录下添加一个cmake文件git_version.cmake,内容如下: # get git hash macro(get_git_hash _git_hash) set(ENV{GIT_ ...

  3. Selenium4+Python3系列(八) - Cookie、截图、单选框及复选框处理、富文本框、日历控件操作

    我所在的城市昨天出了近20+的阳性案例,但这丝毫没有 "影响" 到996的工作时间,当然,也没有影响到我想继续更新文章的决心. 一.cookie常用操作入门 上一篇有写过关于coo ...

  4. php中的try语句

    为了进一步处理异常,我们需要使用try-catch语句----包括Try语句和至少一个的catch语句.任何调用 可能抛出异常的方法的代码都应该使用try语句.Catch语句用来处理可能抛出的异常.以 ...

  5. pyinstaller 打包多个资源文件到一个可执行文件

    前言 pyinstaller -w: 无终端状态 -F: 打包成一个可执行文件 开始 假设 main.py 脚本调用 test.mp4视频文件(main.py和test.mp4在同一级目录),那么将在 ...

  6. github上fork2.4k,star8.7k的这款状态机,原来长这样!

    大家好,我是陶朱公Boy. 前言 上一篇文章<关于状态机的技术选型,最后一个真心好>我跟大家聊了一下关于"状态机"的话题. 于是就有小伙伴私信我,自己项目也考虑引入co ...

  7. Windows及eclipse常用快捷键-小彤在努力

    Windows快捷键 Ctrl+A:全选 Ctrl+S:保存 Ctrl+Z:撤回 Ctrl+X:剪切 Ctrl+C:复制 Ctrl+V:粘贴 Ctrl+F:查找 Windows+E:打开我的电脑 Al ...

  8. SQL注入绕waf思路总结

    1.关键字大小写混合绕过 关键字大小写混合只针对于小写或大写的关键字匹配技术-正则表达式,如果在匹配时大小写不敏感的话,就无法绕过.这是最简单的一个绕过技术. 例如:将union select混写成U ...

  9. 【Shell脚本案例】案例3:批量创建100个用户并设置密码

    一.背景 新入职员工创建用户 二.常规操作 useradd zhangsan ls /home/ password zhangsan 三.考虑问题 1.实现自动输入密码,将其存到文件中 passwor ...

  10. v-if v-for同时使用 解决eslint报错问题

    <template v-for="sec in item.goods"> <div v-if="item.showDetail" class= ...