当前位置:Gxlcms > 数据库问题 > flask实战-个人博客-程序骨架、创建数据库模型、临接列表关系

flask实战-个人博客-程序骨架、创建数据库模型、临接列表关系

时间:2021-07-01 10:21:17 帮助过:11人阅读

personalBlog.extensions import db class Admin(db.Model): id = db.Column(db.Integer, primary_key = True) username = db.Column(db.String(20)) password_hash = db.Column(db.string(128)) blog_title = db.Column(db.string(60)) blog_sub_title = db.Column(db.String(100)) name = db.Column(db.String(30)) about = db.Column(db.Text)

 

除了主键字段(id),管理员模型包含存储用户信息和博客资料的字段:用户姓名(name)、密码散列值(password_hash)、博客标题(blog_title)、博客股标题(blog_sub_title)、关于信息(about)。

 

在这些字段中,我们并没有添加一个password字段来存储密码,取而代之的是一个password_hash字段,后面我们会详细了解具体的原因。

 

当然,在真实的博客平台中,用户还会拥有更多的可定义设置保存在数据库中,比如用来发送提醒邮件的邮箱服务器、每页显示的文章数量等。这里我们的目标是一个尽量简单的博客平台,所以大部分设置都保存在配置文件中。

 

2)分类

用于存储文章分类的数据库模型如下所示:

class Category(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    name = db.Column(db.String(30), unique = True)

分类的名称不允许重复,因此name值将unique参数设为True。

3)文章

存储文章Post模型有标题(title)字段、正文(body)字段以及时间戳(timestamp)字段组成,如下所示:

 

personalBlog/models.py:文章模型

 

from datetime import datetime

class Post(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    title = db.Column(db.String(60))
    body = db.Column(db.Text)
    timestamp = db.Column(db.DateTime, default = datetime.utcnow)

 

 

在分类和文章之间需要建立一对多关系。我们为Post模型添加了一个category_id外键字段,作为指向分类模型的外键,存储分类记录的主键值,同时在Post类中创建标量关系属性category,在category类中创建集合关系属性posts,如下所示:

 

class Category(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    name = db.Column(db.String(30), unique = True)
    posts = db.relationship(Post, back_populates = category)

class Post(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    title = db.Column(db.String(60))
    body = db.Column(db.Text)
    timestamp = db.Column(db.DateTime, default = datetime.utcnow)
    category_id = db.Column(db.Integer, db.ForeignKey(category.id))
    category = db.relationship(Category, back_populates = posts)

 

4)评论

用来存储评论的模型类Comment如下所示:

 

personalBlog/models.py: 评论模型

 

class Comment(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    author = db.Column(db.String(30))
    email = db.Column(db.String(254))
    site = db.Column(db.String(255))
    body = db.Column(db.Text)
    from_admin = db.Column(db.Boolean, default = False)
    reviewed = db.Column(db.Boolean, default = False)
    timestamp = db.Column(db.DateTime, default = datetime.utcnow, index = True)

 

    

除了作者(author)、电子邮件(email)、站点(site)、正文(body)这几个常规字段,Comment模型还包含这两个特殊字段:from_admin字段存储布尔值,用来判断评论是否是管理员的评论,默认为False;reviewed字段也存储布尔值,用来判断评论是否通过审核。

 

添加reviewd字段的主要目的是为了防止垃圾评论和不当评论,当用户发表评论后,评论不会立刻显示在博客中,只有当管理员在博客后台查看并批准后才会显示。

 

每篇文章都可以包含多个评论,文章和评论之间是一对多双向关系:

 

class Post(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    title = db.Column(db.String(60))
    body = db.Column(db.Text)
    timestamp = db.Column(db.DateTime, default = datetime.utcnow)
    category_id = db.Column(db.Integer, db.foreignKey(category.id))
    category = db.relationship(Category, back_populates = posts)
#  cascade:级联操作
    comments = db.relationship(Comment, back_populates = post, cascade = all) 
    

class Comment(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    author = db.Column(db.String(30))
    email = db.Column(db.String(254))
    site = db.Column(db.String(255))
    body = db.Column(db.Text)
    from_admin = db.Column(db.Boolean, default = False)
    reviewed = db.Column(db.Boolean, default = False)
    timestamp = db.Column(db.DateTime, default = datetime.utcnow, index = True)
    post_id = db.Column(db.Integer, db.ForeignKey(post.id))
    post = db.relationship(Post, back_populates = comments)

 

 

Comment模型中创建的外键字段post_id存储Post记录的主键值。我们在这里设置了级联删除,也就是说,当某个记录被删除时,该文章所属的所有评论也会一并被删除,所以在删除文章时不用手动删除对应的评论。

 

2、临接列表关系

与messageBoard不同,博客程序中的评论要支持存储回复。我们想要为评论添加回复,并在获取某个评论时通过关系属性获得相对应的回复,这样就可以在模板中显示出评论之间的对应关系。那么回复如何存储在数据库中呢?

 

你当然可以再为回复创建一个Reply模型,然后使用一对多关系将评论和回复关联起来。但是我们将介绍一个更简单的解决办法,因为回复本身也是评论,如果可以在评论模型内建立层级关系,那么就可以在一个模型中表示评论和回复。

 

这种在同一个模型内的一对多关系在SQLAlchemy中被称为临接列表关系(Adjacency List Relationship)。具体来说,我们需要在Comment模型中添加一个外键指向它自身。这样我们就得到一种层级关系:每个评论对象都可以包含多个评论,即回复。

 

下面是更新后的comment模型:

class Comment(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    author = db.Column(db.String(30))
    email = db.Column(db.String(254))
    site = db.Column(db.String(255))
    body = db.Column(db.Text)
    from_admin = db.Column(db.Boolean, default = False)
    reviewed = db.Column(db.Boolean, default = False)
    timestamp = db.Column(db.DateTime, default = datetime.utcnow, index = True)
    post_id = db.Column(db.Integer, db.ForeignKey(post.id))
    post = db.relationship(Post, back_populates = comments)
    
    replied_id = db.Column(db.Integer, db.ForeignKey(comment.id))
    replied = db.relationship(Comment, back_populates = replies, remote_side = [id])
    replies = db.relationship(Comment, back_populates = replied, cascade = all)

 

 

在Comment模型中,我们添加了一个replied_id字段,通过db.ForeignKey()设置一个外键指向自身的id字段:

replied_id = db.Column(db.Integer, db.ForeignKey(comment.id))

关系两侧的关系属性都在Comment模型中定义,需要特别说明的是表示被回复评论(父对象)的标量关系属性replied的定义。

这个关系和我们之前熟悉的一对多关系基本相同。一对多关系中,我们需要在“多”这一侧定义外键,这样SQLAlchemy就会知道哪边是“多”的一侧。这时关系对“多”这一侧来说就是多对一关系。但是在临接列表关系中,关系的两侧都在同一个模型中,这时SQLAlchemy就无法分辨关系的两侧。在这个关系函数中,通过remote_side参数设为id字段,我们就把id字段定义为关系的远程侧(Remote Side),而replied_id就响应地变为本地侧(Local Side),这样反向关系就被定义为多对一,即多个回复对应一个父评论。

 

集合关系属性replies中的cascade参数设为all,因为我们期望的效果是,当父评论被删除时,所有的自评论也随之删除。

flask实战-个人博客-程序骨架、创建数据库模型、临接列表关系

标签:cas   reply   默认   自身   nal   更新   local   comm   alt   

人气教程排行