项目开发基本流程
1.需求分析
2.架构设计
3.分组开发
4.提交测试
5.交付上线
项目流程
仿博客园项目
核心:文章的增删改查
表分析
先确定表的数量,在确定表的基础字段,最后确定表的外键字段
1.用户表
2.个人站点表
3.文章表
4.文章分类表
5.文章标签表
6.点赞点踩表
7.文章评论表
基础字段分析
用户表
电话号码、头像、注册时间
用户与个人站点是一对一外键关系
个人站点表
站点名称
站点标题
站点样式(cs/js样式)
文章表
文章标题
文章简介
文章内容
发布时间
文章表与个人站点是一对多外键关系
文章表与文章分类是一对多外键关系
文章表与文章标签表是多对多外键关系
'''
数据库字段优化设计:我们想统计文章的评论数 点赞数
通过文章数据跨表查询到文章评论表中对应的数据统计即可
但是文章需要频繁的展示 每次都跨表查询的话效率极低
我们在文章表中再创建三个普通字段
之后只需要确保每次操作评论表或者点赞点踩表时同步修改上述三 个普通字段即可
'''
文章评论数
文章点赞数
文章点踩数
文章分类表
分类名称
文章分类与个人站点是一对多外键关系
文章标签表
标签名称
文章标签与个人站点是一对多外键关系
点赞点踩表:记录哪个用户给那片文章点了赞还是踩
用户字段(用户主键)>>>:外键字段
文章字段(文章主键)>>>:外键字段
点赞点踩
文章评论表:记录哪个用户给哪篇文章评论了什么内容
用户字段(用户主键)>>>:外键字段
文章字段(文章主键)>>>:外键字段
评论内容
评论时间
外键字段(自关联)
表创建
from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
"""用户表"""
phone = models.CharField(max_length=32, verbose_name='电话号码', null=True)
avatar = models.FileField(upload_to='avatar/', default='avatar/default.jpg', verbose_name='用户头像')
register_time = models.DateTimeField(auto_now_add=True, verbose_name='注册时间')
# 用户表与个人站点是一对一
site = models.OneToOneField(to='Site', on_delete=models.CASCADE, null=True)
class Site(models.Model):
"""个人站点表"""
site_name = models.CharField(max_length=32, verbose_name='站点名称')
site_title = models.CharField(max_length=32, verbose_name='站点标题')
site_theme = models.CharField(max_length=255, verbose_name='站点样式', null=True)
class Article(models.Model):
"""文章表"""
title = models.CharField(max_length=64, verbose_name='文章标题')
desc = models.CharField(max_length=255, verbose_name='文章简介')
content = models.TextField(verbose_name='文章内容')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='文章创建时间')
# 特殊字段,优化字段
comment_num = models.BigIntegerField(verbose_name='文章评论数', null=True)
up_num = models.BigIntegerField(verbose_name='文章点赞数', null=True)
down_num = models.BigIntegerField(verbose_name='文章点踩数', null=True)
# 个人站点与文章是一对多
site = models.ForeignKey(to='Site', on_delete=models.CASCADE, null=True)
# 文章表与分类表是一对多
category = models.ForeignKey(to='Category', on_delete=models.CASCADE, null=True)
# 文章与标签表是多对多关系
tags = models.ManyToManyField(to='Tag', through='ArticleToTag', # 指定第三张表
through_fields=('article', 'tag'), # 指定第三表里面的字段
null=True)
class Category(models.Model):
"""文章分类表"""
name = models.CharField(max_length=32, verbose_name='分类名称', null=True)
# 文章分类与个人站点是一对多关系
site = models.ForeignKey(to='Site', on_delete=models.CASCADE, null=True)
class Tag(models.Model):
"""文章标签表"""
name = models.CharField(max_length=32, verbose_name='标签名称', null=True)
# 文章标签与个人站点是一对多关系
site = models.ForeignKey(to='Site', on_delete=models.CASCADE, null=True)
class ArticleToTag(models.Model):
"""文章与标签的多对多表"""
article = models.ForeignKey(to='Article', on_delete=models.CASCADE, null=True)
tag = models.ForeignKey(to='Tag', on_delete=models.CASCADE, null=True)
class UpAndDown(models.Model):
"""点赞点踩表"""
user = models.ForeignKey(to='UserInfo', on_delete=models.CASCADE, null=True)
article = models.ForeignKey(to='Article', on_delete=models.CASCADE, null=True)
is_up = models.BooleanField(verbose_name='点赞点踩')
class Comment(models.Model):
"""文章评论表"""
user = models.ForeignKey(to='UserInfo', on_delete=models.CASCADE, null=True)
article = models.ForeignKey(to='Article', on_delete=models.CASCADE, null=True)
content = models.TextField(verbose_name='评论内容')
comment_time = models.DateTimeField(auto_now_add=True, verbose_name='评论时间')
# 自关联
parent = models.ForeignKey(to='self', on_delete=models.CASCADE, null=True)
注册功能
前端页面:实时查看上传头像
$('#myfile').change(function () {
let myfileReaderobj = new FileReader()
let fileobj = this.files[0]
myfileReaderobj.readAsDataURL(fileobj)
myfileReaderobj.onload = function () {
$('#myimg').attr('src', myfileReaderobj.result)
}
})
发送ajax请求
$('#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',
data: myFormDataobj,
contentType: false,
processData: false,
success: function (args) {
if (args.code === 10000){
window.location.href=args.url
}else{
let dataobj = args.msg;
$.each(dataobj,function (k,msgArray) {
let Eleid = '#id_'+k
$(Eleid).next().text(msgArray[0]).parent().addClass('has-error')
})
}
}
})
})
取消标签的改变
$('input').focus(function (){
$(this).next().text('').parent().removeClass('has-error')
})
登录功能
from PIL import Image, ImageFont, ImageDraw
"""
Image 产生图片
ImageFont 字体样式
ImageDraw 画笔对象
"""
from io import BytesIO, StringIO
"""
BytesIO 在内存中临时存储,读取的时候以bytes格式为准
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', (360, 35), get_random())
io_obj = BytesIO()
img_obj.save(io_obj, 'png')
return HttpResponse(io_obj.getvalue())
标签:name,项目,models,BBS,文章,null,True,verbose
From: https://www.cnblogs.com/zhanghong1229/p/17020491.html