flask_sqlalchemy使用笔记(一)

1. 扩展初始化

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
db = SQLAlchemy(app)

2.数据模型关系

假设我们要为一个博客系统定义关系模型。
首先,系统中要有文章和用户:

#博客文章
class Post(db.Model):
    __tablename__ = 'post' #定义表名, 表明默认为类名小写,所以本行删去也可以
    id = db.Column(db.Integer, primary_key=True)  #定义主键
    body = db.Column(db.Text)


#用户
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, index=True) #定义长度和其他参数
    

(db.Model是一个基类,具有__tablename__, query等属性。)

如何体现用户和文章之间的关系呢?假设一篇文章只有由一名用户编写,一名用户可以编写多篇文章。这是一个典型的一对多关系。定义这样的关系需要两步。

1.在多侧定义外键

class Post(db.Model):
    ...
    author_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    #   外键  = db.Column(字段类型, db.ForeignKey(另一侧表名.主键字段名)

2.在出发侧("一侧")定义关系属性

class User(db.Model):
    ...
    posts = db.relationship('Post') 
    #集和关系属性 = db.relationship('另一侧类名')  #这里使用类名,表明返回对象的类型

这样,调用某个User对象的posts关系属性,就能得到一个与之相对应的Post对象列表,其author_id值与这个User对象的id值相等。

同理,在Post对象中,也可以定义类似的author属性。这样,可以获取一篇博客文章对应的作者,也可以获取一名用户的多篇文章了。在Post类中添加相应的关系字段:

class Post(db.Model):
    ...
    author_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    author = db.relationship('User')

似乎这样就行了,但是这样做的问题在于修改其中一个对象实例的字段并不会自动更新另一个类型对应的字段。例如:

>>> user = User()
>>> post = Post()
>>> post.author = user
>>> print(user.posts)
[]

尽管更新了post的author字段,user的posts字段依然为空,而在逻辑上,用户的文章字段和文章的作者字段是彼此关连的,在其中一方更新时,另一方应该同时更新为好。这是一个双向的关系,使用back_populates参数就可以实现:

class User(db.Model):
    ...
    posts = db.relationship('Post', back_populates='author')


class Post(db.Model):
    ...
    author_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    author = db.relationship('User', back_populates='posts')
    #集和关系属性 = db.relationship('另一侧类名', back_populates='另一侧相关联的属性名')

使用backref参数可以实现同样的效果,但是更加简化:

class User(db.Model):
    ...
    posts = db.relationship('Post', backref='author')
    #集和关系属性 = db.relationship('另一侧类名',backref='在另一侧自动生成的相关联的属性名')

class Post(db.Model):
    ...
    author_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    #此处Post已具备author属性

不过本着“显式优于隐式”,还是使用back_populates为宜。

3.级联

cascade,在操作一个对象时对相关的对象也采取某些操作。在博客系统中,博客文章与文章评论就是一个例子。单独存在的一条评论是没有意义的。文章评论(子)关联并依赖于博客文章(父),在文章被添加到数据库时,相关评论也被添加;文章被删除时,评论也没有存在于数据库的必要了;若评论与文章解除了关联,成为了孤立对象(orphan object(孤儿对象2333)),评论也应被删除。

级联行为通过关系函数relationship()的cascade参数设置。上述三种情况分别对应save-update,delete和delete-orphan参数值。参数值可组合。其余参数值及其详细解释可见Sqlalchemy文档:cascades

class Post(db.Model):
    ...
    comments = db.relationship('Comment',back_populates='post',
                                         cascade="all, delete-orphan")
    #all = save-update + merge + delete


class Comments(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    body = db.Column(db.Text)
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
    post = db.relationship('Post', back_populates='comments')

你可能感兴趣的