Flasksqlalchemy一对多与多对一与一对一及多对多关系介绍_第1页
Flasksqlalchemy一对多与多对一与一对一及多对多关系介绍_第2页
Flasksqlalchemy一对多与多对一与一对一及多对多关系介绍_第3页
Flasksqlalchemy一对多与多对一与一对一及多对多关系介绍_第4页
Flasksqlalchemy一对多与多对一与一对一及多对多关系介绍_第5页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第Flasksqlalchemy一对多与多对一与一对一及多对多关系介绍目录配置项定义外键定义关系属性双向的关系属性使用关系属性添加数据一对一多对多这里以作者和文章来演示一对多的关系:一个作者可以有多篇文章,但是一篇文章只能有一个作者。

配置项

首先,配置下数据库config.py

username='xxxx'

password='xxxx'

database='school'

hostname='localhost'

port='3306'

uri=f'mysql+pymysql://{username}:{password}@{hostname}:{port}/{database}'

SQLALCHEMY_DATABASE_URI=uri

SQLALCHEMY_TRACK_MODIFICATIONS=False

在app.py文件中导入配置

fromflaskimportFlask

fromflask_sqlalchemyimportSQLAlchemy

importconfig

app=Flask(__name__)

app.config.from_object(config)

db=SQLAlchemy(app)

接着创建模型类,建立python类到数据表的映射:

定义外键

classUser(db.Model):

__tablename__='user'

id=db.Column(db.Integer,primary_key=True,autoincrement=True)

name=db.Column(db.String(100),nullable=False)

classArticle(db.Model):

__tablename__='article'

id=db.Column(db.Integer,primary_key=True,autoincrement=True)

title=db.Column(db.String(200),nullable=False)

content=db.Column(db.Text,nullable=False)

user_id=db.Column(db.Integer,db.ForeignKey('user.id'))

由于一个作者可以有多篇文章,所以外键应该设置在Article类中,这样每一篇文章的user_id字段都只会有一个值,因为只对应一个作者。

假设,在User类中存在外键字段article_id,那么一个作者的所有文章都需要存放在这一个字段中,但是外键只能存放单一数据(表量),所以外键的设置总是在多的这一侧定义。

定义关系属性

为什么需要关系属性,具体的原因我也不清楚,我想可能是从查询的角度来说,会更方便。

定义关系属性需要使用关系函数。关系属性在关系的出发侧定义,即一对多关系的一这一侧。一个作者拥有多篇文章,我们在User模型类中,定义一个叫articles的关系属性,用它可以表示每一个作者所对应的多篇文章。

classUser(db.Model):

__tablename__='user'

id=db.Column(db.Integer,primary_key=True,autoincrement=True)

name=db.Column(db.String(100),nullable=False)

articles=db.relationship('Article',backref=db.backref('user'))

articles字段使用db.relationship()关系函数定义为关系属性,这个关系属性将返回多个记录。

relationship()函数的第一个参数为关系另一侧的模型名称,是python类的名称,不是数据表名称。第二个参数表示添加反向引用,会自动在另一侧,也就是Article模型中,建立一个关系属性,这个字段叫user,使用这个字段可以查找到文章所对应的用户。

现在user表中多了一个字段articles,但是它并不是数据库层面的,实际的表中并没有这个字段,可以认为只是一个查询接口。

接着创建数据表并插入数据:

u1=User(name='zs')

a1=Article(title='西游记',content='西游记是四大名著')

a1.author=u1

db.session.add(a1)

mit()

创建了一个user表的记录,一个article表的记录,如何让他们建立联系呢?使用关系属性字段:

文章唯一指向一个作者:

a1.author=u1

直接将作者的实例对象u1赋值给文章实例对象a1的author字段,他们就会建立关系,文章表中的user_id字段就会指向那个作者。

article表

user表

现在用户zs拥有两篇文章,尝试使用关系属性查询。

u1=User.query.filter_by(name='zs').first()

print(u1.articles)

输出user表的articles字段:

[Article1,Article2]

可以发现这个字段里面是两条记录,是article表中的两条记录,因为这两篇文章都是zs的文章,所以通过这个关系属性字段,可以获取到一个作者对应的所有文章。

反过来,关于反向引用,backref=db.backref(user),它会在Article也建立一个关系属性,这个字段叫做user,可以通过这个字段获取到文章对应的作者。

比如:

#先找到文章

article1=Article.query.filter_by(title='西游记').first()

#使用反向引用的字段,user,获取到这个文章对应的作者

print(article1.user)

输出:

User1

双向的关系属性

上面在建立关系属性是,只是在User类中使用了关系属性:

articles=db.relationship('Article',backref=db.backref('user'))

这种方式,会隐式的在Article类中也建立一个关系属性user。我们可以使用back_populates参数显式的建立双向的关系属性。

这里仍然以作者author和文章article为例,一个作者可以有多篇文章,一篇文章只能有一个作者,建立显示的双向关系属性。

classUser(db.Model):

__tablename__='author'

id=db.Column(db.Integer,primary_key=True,autoincrement=True)

name=db.Column(db.String(100),nullable=False)

#关系属性

articles=db.relationship('Article',back_populates='authors')

classArticle(db.Model):

__tablename__='article'

id=db.Column(db.Integer,primary_key=True,autoincrement=True)

title=db.Column(db.String(200),nullable=False)

content=db.Column(db.Text,nullable=False)

auth_id=db.Column(db.Integer,db.ForeignKey('author.id'))

#关系属性

authors=db.relationship('User',back_populates='articles')

在一的一侧,User类中,建立了关系属性,articles,获取一个作者对应的多个文章记录。

在多的一侧,Article类中,建立了关系属性,authors,获取每一篇文章对应的一个作者记录。

使用back_populates参数连接对方,参数值需要设置为关系另一侧的关系属性名。

使用关系属性添加数据

u1=User(name='zs')

a1=Article(title='西游记',content='西游记是四大名著')

a2=Article(title='红楼梦',content='红楼梦是四大名著')

a1.authors=u1

a2.authors=u1

db.session.add_all([a1,a2])

mit()

实例化User类对象u1,Article类对象a1,a2。

然后使用Article类的关系属性字段,authors

将User类对象u1赋值给Article类对象的关系属性authors

或者反过来,使用用户的关系属性字段articles添加数据:

definsert():

u1=User(name='zs')

a1=Article(title='西游记',content='西游记是四大名著')

a2=Article(title='水浒传',content='水浒传是四大名著')

u1.articles=[a1,a2]

db.session.add(u1)

mit()

这里的添加方式是:u1.articles=[a1,a2]

接着查询,使用关系属性字段就可以查询到了,这里只是演示了使用back_populates参数显示的建立双向的关系属性,之前使用的backref可以简化关系的定义,是一种隐式的双向关系的建立。

一对一

这里使用国家和首都演示一对一关系:每一个国家只有一个首都;反过来说,一个城市也只能作为一个国家的首都。

一对一关系实际上是通过建立双向关系的一对多关系的基础上转化而来的。

classCountry(db.Model):

__tablename__='country'

id=db.Column(db.Integer,primary_key=True,autoincrement=True)

name=db.Column(db.String(30),unique=True)

capital=db.relationship('Capital',back_populates='country')

classCapital(db.Model):

__tablename__='capital'

id=db.Column(db.Integer,primary_key=True,autoincrement=True)

name=db.Column(db.String(30),unique=True)

#外键在哪一个表中设置应该都可以

country_id=db.Column(db.Integer,db.ForeignKey('country.id'))

#设置关系属性

country=db.relationship('Country',back_populates='capital')

首先上面是一个双向的关系属性,这时候表的关系和之前的一对多没有区别,现在我们需要给关系属性中假如一个参数uselist=False

在一的一侧加入,就是在Country类模型中加入

capital=db.relationship('Capital',back_populates='country',uselist=False)

加入这个参数以后,在使用Country.capital获取记录时,将限制只返回一条记录。

由于Capital中设置了外键country_id,存储单一数据,一个记录的country_id只会对应Country中的一个记录。

这是一对多关系就变成了一对一关系。

测试一对一:

首先插入数据,插入一个国家记录,一个城市记录,然后建立关系。

definsert():

china=Country(name='中国')

Beijing=Capital(name='北京')

Beijing.country=china

db.session.add(Beijing)

mit()

这样,Country表中就有了

capital表中:

他们目前时一对一的关系,那么,假如现在新增一个城市,它的country_id指向中国,

这时候就变成了一个国家,对应两个城市,变成了一对多,但是我们定义的是一对一,这样可行吗?

deff():

#首先拿到中国的这条记录

china=Country.query.filter_by(name='中国')

china=china.first()

print(china)

#新增城市,

Guangzhou=Capital(name='广州')

#建立广州与中国之间的关系

Guangzhou.country=china

db.session.add(Guangzhou)

mit()

print('success')

执行这个函数之后,数据表会有以下变化:

可以看到capital表中的北京这条记录的country_id值变成了NULL,这正是因为我们建立的关系时一对一的,不允许变成一对多,所以,会把之前的对应关系取消掉。假如删除了参数uselist=False,就可以建立一对多的关系了。

多对多

这里使用学生和老师来演示多对多关系:每个学生有多个老师,每个老师也可以有多个学生。

在一对多关系中,我们可以在多这一侧添加外键指向一这一侧,外键只能存储一个记录,但是在多对多关系中,每一个记录都可以与关系另一侧的多个记录建立关系,关系两侧的模型都需要存储一组外键。

在SQLAlchemy中,要想表示多对多关系,除了关系两侧的模型外,我们还需要创建一个关联表(associationtable)。关联表不存储数据,只用来存储关系两侧模型的外键对应关系,

fromflaskimportFlask

fromflask_sqlalchemyimportSQLAlchemy

importconfig

app=Flask(__name__)

app.config.from_object(config)

db=SQLAlchemy(app)

association_table=db.Table('stu_tea_associ',#关联表的名称

db.Column('student_id',db.Integer,db.ForeignKey('student.id')),#字段student_id,类型,关联的外键

db.Column('teacher_id',db.Integer,db.ForeignKey('teacher.id')))#字段teacher_id,类型,关联的外键

classStudent(db.Model):

__tablename__='student'

id=db.Column(db.Integer,primary_key=True,autoincrement=True)

name=db.Column(db.String(20))

#建立关系属性

teachers=db.relationship('Teacher',secondary=association_table,back_populates='students')

classTeacher(db.Model):

__tablename__='teacher'

id=db.Column(db.Integer,primary_key=True,autoincrement=True)

name=db.Column(db.String(20))

#建立关系属性

students=db.relationship('Student',secondary=association_table,back_populates='teachers')

关联表使用db.Table类定义,传入的第一个参数是关联表的名称。我们在关联表中定义了两个字段student_id,teacher_id,这两个字段作为外键,与student.id,t

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论