博客系统项目流程
一、搞清楚需求(产品经理)
(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文件:
四、功能测试
五、项目部署上线
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术