一、项目开发流程
# 1.需求分析
架构师+产品经理+开发组组长
在跟客户谈需求之前,会大致先了解客户的需求,然后自己先设计一套比较好写的方案,在跟客户沟通
交流中引导客户往我们之前想好的方案上面靠,形成一个初步的方案
# 2.项目设计
架构师:编程语言选择,框架选择,数据库选择,功能划分,项目报价
# 3.分组开发
组长找组员开会,安排各自功能的模块
# 4.测试
# 5.交付上线
1.交给对方的运维人员
2.直接上线到我们的服务器上,收取维护费用
二、表设计
一个项目中最重要的不是业务逻辑的书写,而是前期的表设计。
BBS表设计:
1.用户表
继承AbstractUser
拓展:
phone 手机号
avatar 用户头像
create_time 创建时间
外键字段:
一对一个人站点表
2.个人站点表
site_name 站点名称
site_title 站点标题
site_theme 站点样式
3.文章标签表
name 标签名
外键字段:
一对多个人站点
4.文章分类表
name 分类名
外键字段:
一对多个人站点
5.文章表
title 文章标题
desc 文章简介
content 文章内容
create_time 发布时间
up_num 点赞数
down_num 点踩数
comment_num 评论数
外键字段:
一对多个人站点
多对多文章标签
一对多文章分类
6.点赞点踩表
user 用户 ForeignKey(to="User")
article 文章 ForeignKey(to="Article")
is_up 是否点赞点踩 BooleanField
7.文章评论表
user 用户 ForeignKey(to="User")
article 文章 ForeignKey(to="Article")
content 评论 CharField()
comment_time 评论时间 DateField()
# 自关联
parent ForeignKey(to="self",null=True)
三、创建表
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class UserInfo(AbstractUser):
phone = models.BigIntegerField(verbose_name='手机号', null=True)
# 头像
avatar = models.FileField(upload_to='avatar/', default='avatar/default.png', verbose_name='用户头像')
"""给avatar字段传入文件对象,该文件会自动存储到avatar文件下,然后avatar字段只保存文件路径avatar/default.png"""
create_time = models.DateField(auto_now_add=True)
blog = models.OneToOneField(to='Blog', on_delete=models.CASCADE, null=True)
class Blog(models.Model):
site_name = models.CharField(verbose_name='站点名称', max_length=32)
site_title = models.CharField(verbose_name='站点标题', max_length=32)
# 简单模拟,认识样式内部原理的操作
site_theme = models.CharField(verbose_name='站点样式', max_length=64) # 存css/js的文件路径
class Category(models.Model):
name = models.CharField(verbose_name='文章分类', max_length=32)
blog = models.OneToOneField(to='Blog', on_delete=models.CASCADE, null=True)
class Tag(models.Model):
name = models.CharField(verbose_name='文章标签', max_length=32)
blog = models.OneToOneField(to='Blog', on_delete=models.CASCADE, null=True)
class Article(models.Model):
title = models.CharField(verbose_name='文章标题', max_length=64)
desc = models.CharField(verbose_name='文章简介', max_length=255)
# 文章内容有很多,一般情况下都是使用TextField
content = models.TextField(verbose_name='文章内容')
create_time = models.DateField(auto_now_add=True)
up_num = models.BigIntegerField(verbose_name='点赞数', default=0)
down_num = models.BigIntegerField(verbose_name='点踩数', default=0)
comment_num = models.BigIntegerField(verbose_name='评论数', default=0)
# 外键字段
blog = models.OneToOneField(to='Blog', on_delete=models.CASCADE, null=True)
category = models.ForeignKey(to='Category', null=True, on_delete=models.CASCADE)
tags = models.ManyToManyField(to='Tag', through='Article2Tag', through_fields=('article','tag'))
class Article2Tag(models.Model):
article = models.ForeignKey(to='Article', on_delete=models.CASCADE)
tag = models.ForeignKey(to='Tag', 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)
is_up = models.BooleanField() # 传布尔值 存0/1
class Comment(models.Model):
user = models.ForeignKey(to='UserInfo', on_delete=models.CASCADE)
article = models.ForeignKey(to='Article', on_delete=models.CASCADE)
content = models.CharField(verbose_name='评论内容', max_length=255)
comment_time = models.DateTimeField(verbose_name='评论时间', auto_now_add=True)
# 自关联
parent = models.ForeignKey(to='self', null=True, on_delete=models.CASCADE)
四、forms组件书写
# 书写针对用户表的forms组件代码
from django import forms
from app01 import models
class MyRegForm(forms.Form):
username = forms.CharField(label='用户名', min_length=3, max_length=8,
error_messages={
'required': "用户名不能为空",
'min_length': "用户名最少3位",
'max_length': "用户名最大8位"
},
widget=forms.TextInput(attrs={'class': 'form-control'})
)
password = forms.CharField(label='密码', min_length=3, max_length=8,
error_messages={
'required': "密码不能为空",
'min_length': "密码最少3位",
'max_length': "密码最大8位"
},
widget=forms.PasswordInput(attrs={'class': 'form-control'})
)
confirm_password = forms.CharField(label='确认密码', min_length=3, max_length=8,
error_messages={
'required': "确认密码不能为空",
'min_length': "确认密码最少3位",
'max_length': "确认密码最大8位"
},
widget=forms.PasswordInput(attrs={'class': 'form-control'})
)
email = forms.EmailField(label='邮箱',
error_messages={
'required': "邮箱不能为空",
'invalid': "邮箱格式不正确"
},
widget=forms.EmailInput(attrs={'class': 'form-control'})
)
# 钩子函数
# 局部钩子:校验用户名是否已存在
def clean_username(self):
username = self.cleaned_data.get('username')
# 去数据库中校验
is_exist = models.UserInfo.objects.filter(username=username)
if is_exist:
# 提示信息
self.add_error('username', '用户名已存在')
return username
# 全局钩子:校验两次密码是否一致
def clean(self):
password = self.cleaned_data.get('password')
confirm_password = self.cleaned_data.get('confirm_password')
if not password == confirm_password:
self.add_error('confirm_password', '两次密码不一致')
return self.cleaned_data
五、media配置
该配置可以让用户上传的所有文件固定存放在某一个指定的文件下
# 配置用户上传的文件存储位置
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # 文件名无所谓
会自动创建多级目录