博客系统项目流程

一、搞清楚需求(产品经理)

  (1)基于用户认证组件和Ajax实现登录验证(图片验证码)

  (2)基于forms组件和Ajax实现注册功能

  (3)设计系统首页(文章列表渲染)

  (4)设计个人站点页面(跨表查询、分组查询)

  (5)文章详情页

  (6)实现文章点赞功能(Ajax)

  (7)实现文章评论功能:涉及文章的评论和评论的评论

  (8)富文本编辑框和防止xss攻击

二、设计博客园表结构

  博客系统表结构流程图

  流程图地址:https://www.processon.com/diagraming/5b529154e4b0f8477d8d0d9d

  

三、创建项目与迁移表

1、根据表结构图在models.py中创建模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
from django.db import models
 
# Create your models here.
from django.contrib.auth.models import AbstractUser
 
 
class UserInfo(AbstractUser):
    """
    用户信息表:
    使用用户认证组件,用户表的字段不够用,需要继承AbstractUser类来定制一个自己的用户表。
    在继承后,不再生成auth_user表,直接使用user_info表
    """
    nid = models.AutoField(primary_key=True)
    telephone = models.CharField(max_length=11, null=True, unique=True)
    avatar = models.FileField(upload_to='avatars/', default="/avatars/default.png")   # 该字段存放每个用户的头像文件
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)   # auto_now_add字段:这个创建时间不用赋值,默认用当前时间赋值
 
    blog = models.OneToOneField(to='Blog', to_field='nid', null=True, on_delete=models.CASCADE)  # 站点表和用户表一对一关系
 
    def __str__(self):
        return self.username
 
 
class Blog(models.Model):
    """
    博客信息表(站点)
    用户和站点一对一关系,
    """
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name='个人博客标题', max_length=64)
    site_name = models.CharField(verbose_name='站点名称', max_length=64)
    theme = models.CharField(verbose_name='博客主题', max_length=32)
 
    def __str__(self):
        return self.title
 
 
class Category(models.Model):
    """
    博主个人文章分类表:Linux、python、面试心得、鸡汤
    分类表和用户表是多对一的关系,由于用户和站点是一对一,分类表与站点也是多对一的关系
    """
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name='分类标题', max_length=32)
    blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid', on_delete=models.CASCADE)
 
    def __str__(self):
        return self.title
 
 
class Tag(models.Model):
    """
    标签
    站点和标签绑定的是一对多的关系
    """
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name='标签名称', max_length=32)
    blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid', on_delete=models.CASCADE)
 
    def __str__(self):
        return self.title
 
 
class Article(models.Model):
    """
    文章表
    分类和文章的关系在这里设置为一对多关系(为了与文章和标签关系形成区分)
    用户和文章是一对多的关系
    标签与文章是多对多的关系(用中介模型创建第三张表)
    """
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=50, verbose_name='文章标题')
    desc = models.CharField(max_length=255, verbose_name='文章描述')   # 摘要
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)   # 发布时间
    content = models.TextField()  # 文章内容
 
    # comment_count = models.IntegerField(default=0)
    # up_count = models.IntegerField(default=0)
    # down_count = models.IntegerField(default=0)
 
    user = models.ForeignKey(verbose_name='作者', to='UserInfo', to_field='nid', on_delete=models.CASCADE)
    category = models.ForeignKey(to='Category', to_field='nid', null=True, on_delete=models.CASCADE)
    tags = models.ManyToManyField(    # 中介模型创建第三张关系表
        to="Tag",
        through='Article2Tag',
        through_fields=('article', 'tag'),
    )
 
    def __str__(self):
        return self.title
 
 
class Article2Tag(models.Model):
    """
    文章和标签关系表
    """
    nid = models.AutoField(primary_key=True)
    article = models.ForeignKey(verbose_name='文章', to="Article", to_field='nid', on_delete=models.CASCADE)
    tag = models.ForeignKey(verbose_name='标签', to="Tag", to_field='nid', on_delete=models.CASCADE)
 
    class Meta:
        unique_together = [   # 联合唯一,两个字段不能重复
            ('article', 'tag'),
        ]
 
    def __str__(self):
        v = self.article.title + "---" + self.tag.title
        return v
 
 
class ArticleUpDown(models.Model):
    """
    文章点赞表
    哪个用户对哪个文章点赞或点灭
    """
    nid = models.AutoField(primary_key=True)
    user = models.ForeignKey('UserInfo', null=True, on_delete=models.CASCADE)
    article = models.ForeignKey("Article", null=True, on_delete=models.CASCADE)
    is_up = models.BooleanField(default=True)   # True:赞,  False:灭
 
    class Meta:
        unique_together = [
            ('article', 'user'),
        ]
 
 
class Comment(models.Model):
    """
    评论表
    根评论:对文章的评论
    子评论:对评论的评论
    哪一个用户对哪一篇文章在什么时间做了什么评论内容
    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
    """
    nid = models.AutoField(primary_key=True)
    article = models.ForeignKey(verbose_name='评论文章', to='Article', to_field='nid', on_delete=models.CASCADE)
    user = models.ForeignKey(verbose_name='评论者', to='UserInfo', to_field='nid', on_delete=models.CASCADE)
    content = models.CharField(verbose_name='评论内容', max_length=255)
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
 
    # parent_comment = models.ForeignKey("Comment")   # 关联Comment表,本身就在Comment表中,因此是自关联
    parent_comment = models.ForeignKey('self', null=True, on_delete=models.CASCADE)   # 设置null=True,为null的情况不用存值了
 
    def __str__(self):
        return self.content

2、修改数据库配置

settings.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# DATABASES = {
#     'default': {
#         'ENGINE': 'django.db.backends.sqlite3',
#         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
#     }
# }
 
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'cnblog',     # 要连接的数据库,连接前需要创建好
        'USER': 'root',       # 连接数据库的用户名
        'PASSWORD': '1234',   # 连接数据库的密码
        'HOST': '127.0.0.1'# 连接主机,默认本机
        'PORT': 3306          # 端口  默认3306
    }
}

3、创建数据库

  

4、数据库迁移

  (1)注意在迁移前检查settings.py文件中,INSTALLED_APPS配置中是否自动加入了当前的APP:blog。

  (2)另外由于在models.py中,用户表继承的是原生用户表:AbstractUser,因此必须要在settings.py中做如下设置:

1
AUTH_USER_MODEL = 'blog.UserInfo'

  执行数据库迁移操作:

1
$ python3 manage.py makemigrations

  (3)执行报错:no module named MySQLdb 。这是因为django默认你导入的驱动是MySQLdb,可是MySQLdb 对于py3有很大问题,所以我们需要的驱动是PyMySQL ,所以要在/cnblog/cnblog/__init__.py里面写入:

1
2
import pymysql
pymysql.install_as_MySQLdb()

  (4)执行数据库迁移操作,完成数据库迁移

1
2
$ python3 manage.py makemigrations
$ python3 manage.py migrate

  (5)在pycharm中配置数据库

  

  (6)查看数据库中创建的表

  

  可以看到auth_user表已经没有了,user_info表中包含原生的字段和扩展的字段。user_info表既是用户认证组件的user表也是自己的用户表。

三、按着每一个功能进行开发

1、创建和配置静态文件目录

  在项目根目录下创建static 的python package。并在static下创建子目录blog用于存放博客系统静态文件。

  在settings.py中配置静态文件目录:

1
2
3
4
5
6
7
8
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/
 
STATIC_URL = '/static/'    # 别名
 
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static")    # 实际路径
]

  配置好后,别名'/static/'就指代的是.../cnblog/static/目录了。

  拷入bootstrap文件:

  

 

 

四、功能测试

五、项目部署上线

部署基于python语言的WEB发布环境

 

posted @   休耕  阅读(2382)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示