项目开发流程
1 项目分类
-针对互联网用户:抖音,淘宝 sanic
-产品经理
-公司内部,给用户定制软件
2 项目开发模式分类
-瀑布开发模式
-敏捷开发:devops ci cd
3 项目开发流程
-立项
-需求分析(产品经理提,用户提的需求)
-原型图(流程图,产品经理设计)
-美工切图
-技术选型,数据库架构设计
-前后台开发(开发:协同开发:git)
-开发完成---运维上线---联调(测试环境)
-测试测试
-修改bug(开发)
-上线运行
-迭代更新(开发)
4 多人博客项目(仿cnblogs),功能,需求(前后端混合)
-注册(froms,ajax提交,上传头像)
-登录功能(ajax提交,错误信息渲染)
-首页(列出所有文章,作者头像,发布时间,点赞数。。广告位,轮播图)
-个人站点(左侧过滤,inclusion_tag)
-文章展示
-点赞,点踩功能
-评论功能
-后台管理:展示我的所有文章
-文章新增(修改,删除),防止xss攻击
-修改密码,头像,个人信息(不讲)
2 bbs表分析
# https://gitee.com/xuexianqi/django_blog
# 设计程序(django2.2.2+mysql5.7)
# 数据库设计(设计表)
# 所有的表
-用户表(auth的扩展)
-头像字段
-blog字段
-博客表(个人站点):跟用户一对一
-博客标题
-博客名称
-博客样式
-文章表
-文章标题
-文章摘要
-文章内容
-创建时间
-user_id
-分类id
-标签多对多关系(没有字段)
-分类表
-分类id
-分类名字
-blog字段
-标签表
-标签id
-标签名字
-blog字段
-点赞点踩表
-user_id
-article_id
-is_up:点赞点踩字段
-时间
-评论表
-user_id
-article_id
-评论内容
# 自关联
评论id 用户id 文章id 评论内容 评论id
1 1 1 写的真好 null
2 2 1 明明写的不好 1
3 1 1 你他吗去死 2
4 3 1 就是写的不好 1
3 bbs表模型创建
from django.db import models
# Create your models here.
from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
phone = models.CharField(max_length=32,null=True,default='123')
# upload_to文件上传以后存放的路径
# FileField本质是varchar类型
# 坑()
avatar = models.FileField(upload_to='avatar/', default='avatar/default.png')
# avatar = models.CharField()
blog = models.OneToOneField(to='Blog',on_delete=models.CASCADE,null=True)
class Blog(models.Model):
site_title = models.CharField(max_length=32)
site_name = models.CharField(max_length=32)
# 每个人样式不同(文件地址)
site_style = models.CharField(max_length=32)
def __str__(self):
return self.site_title
class Meta:
#admin进入以后看到的名字
verbose_name_plural='博客表'
class Tag(models.Model):
name = models.CharField(max_length=32)
blog = models.ForeignKey(to='Blog',on_delete=models.CASCADE)
def __str__(self):
return self.name
class Meta:
verbose_name_plural='标签表'
class Category(models.Model):
name = models.CharField(max_length=32)
blog = models.ForeignKey(to='Blog',on_delete=models.CASCADE)
def __str__(self):
return self.name
class Article(models.Model):
title = models.CharField(max_length=32,verbose_name='文章标题')
desc = models.CharField(max_length=128,verbose_name='文章摘要',help_text='小伙子,这里填文章摘要')
# 大文本
content = models.TextField()
create_time = models.DateTimeField(auto_now_add=True)
# 优化字段,减少数据库查询操作,评论数,点赞数
# up_num=models.IntegerField(default=0)
# down_num=models.IntegerField(default=0)
# commit_num=models.IntegerField(default=0)
# 关联关系
blog = models.ForeignKey(to='Blog',on_delete=models.CASCADE)
category = models.ForeignKey(to='Category',on_delete=models.CASCADE)
# 多对多关系
tag = models.ManyToManyField(to='Tag', through='TagToArticle', through_fields=('article', 'tag'))
def __str__(self):
try:
return self.title+'-------'+self.blog.site_title
except:
return self.title
class Meta:
verbose_name_plural = '文章管理'
class TagToArticle(models.Model):
tag = models.ForeignKey(to='Tag',on_delete=models.CASCADE)
article = models.ForeignKey(to='Article',on_delete=models.CASCADE)
class UpAndDown(models.Model):
user = models.ForeignKey(to='UserInfo',on_delete=models.CASCADE)
article = models.ForeignKey(to='Article',on_delete=models.CASCADE)
# 实质存的时候,是0和1
is_up = models.BooleanField()
create_time = models.DateTimeField(auto_now_add=True)
class Commit(models.Model):
user = models.ForeignKey(to='UserInfo',on_delete=models.CASCADE)
article = models.ForeignKey(to='Article',on_delete=models.CASCADE)
content = models.CharField(max_length=256)
create_time = models.DateTimeField(auto_now_add=True)
# 存父评论的id号
# commit_id=models.IntegerField()
# commit=models.ForeignKey(to='Commit')
# 自关联
commit_id=models.ForeignKey(to='Commit',on_delete=models.CASCADE,null=True)
4 注册forms类编写
第一步:创建编辑的文件夹 blog_forms.py
第二部:渲染前端页面 static
配置脚本文件settings.py
STATICFILES_DIRS=[
os.path.join(BASE_DIR,'static')
]
注册页面的搭建register.html
第三步配置路由:urls.py
from blog import views
urlpatterns = [
path('register/', views.register),
]
第四步视图函数的配置:views.py
第五步完善前端页面的渲染:
from django import forms
from django.forms import widgets
class RegisterForm(forms.Form):
username = forms.CharField(max_length=18, min_length=3,label='用户名',
error_messages={'required': '该字段必填',
'max_length': '太长了',
'min_length': '太短了'},
widget=widgets.TextInput(attrs={'class': 'form-control'}))
password = forms.CharField(max_length=18, min_length=3,label='密码',
error_messages={'required': '该字段必填',
'max_length': '太长了',
'min_length': '太短了'},
widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
re_password = forms.CharField(max_length=18, min_length=3,label='确认密码',
error_messages={'required': '该字段必填',
'max_length': '太长了',
'min_length': '太短了'},
widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
email = forms.EmailField(label='邮箱',error_messages={'required': '该字段必填',
'invalid': '不符合邮箱格式'},
widget=widgets.EmailInput(attrs={'class': 'form-control'}))
5 注册功能前端搭建
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
<script src="/static/jquery-3.3.1.js"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">注册功能</h3>
</div>
<div class="panel-body">
<form id="my_form">
{% for item in form %}
<div class="form-group">
<label for="{{ item.auto_id }}">{{ item.label }}</label>
{{ item }}
<span></span>
</div>
{% endfor %}
<div class="form-group">
<label for="myfile">头像
<img src="/static/img/default.png" id='id_img' width="80px" height="80px" style="margin-left: 20px">
</label>
<input type="file" id="myfile" style="display:none;">
</div>
<div class="text-center">
<input type="button" value="注册" class="btn btn-warning">
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</body>
<script>
$('#myfile').change(function () {
//取到文件
let myfile=$(this)[0].files[0]
//let myfile=$('#myfile')
//借助文件阅读器对象,把文件读到这个对象中
let filereader=new FileReader()
filereader.readAsDataURL(myfile)
//等待读完,把它放到img标签上
filereader.onload=function () {
$('#id_img').attr('src',filereader.result)
}
//$('#id_img').attr('src','https://upload-images.jianshu.io/upload_images/9522239-c31b38a1a9913ac4.png?imageMogr2/auto-orient/strip|imageView2/2/w/202/format/webp')
})
</script>
</html>
6 头像实时显示
<script>
$('#myfile').change(function () {
//取到文件
let myfile=$(this)[0].files[0]
//let myfile=$('#myfile')
//借助文件阅读器对象,把文件读到这个对象中
let filereader=new FileReader()
filereader.readAsDataURL(myfile)
//等待读完,把它放到img标签上
filereader.onload=function () {
$('#id_img').attr('src',filereader.result)
}
//$('#id_img').attr('src','https://upload-images.jianshu.io/upload_images/9522239-c31b38a1a9913ac4.png?imageMogr2/auto-orient/strip|imageView2/2/w/202/format/webp')
})
</script>
补充
1 Django:django的orm,rbac,admin
-admin:bug级的存在,几乎不用写代码,就可以撸出一个后台管理系统
-xadmin:django3.0以后,作者弃坑,不管了 1.x版本 2.x版本:用起来还是可以的
-3.x版本:simpleui
2 flask
----------同步框架-------
----------django 3.x以后支持异步------
---------一旦用了异步,所有的都要用异步-----
-python线程中只要有io操作,就会让出gil锁,这条线程下次要执行必须再拿到gil
-协程:单线程下实现并发,程序员自己控制切换
-----往下的是异步框架------
3 tornado:2.x
4 FastAPI:操作数据库
5 Sanic:python 3.5以上,不支持windows
6 到目前为止没有一个好用的异步orm框架
7 异步操作模块:mysql,redis,mongodb
mac,乌班图(台式机),使用window远程连接linux开发,纯windows