Flask开发(二十三)Flask访问数据库 创建关联表
本篇导读:
- 使用Falsk-SQLAlchemy创建一对一的关系表
- 使用Falsk-SQLAlchemy创建一对多的关系表
- 使用Falsk-SQLAlchemy创建多对多的关系表
数据库实体间有3种关系:一对一,一对多,多对多。一个学生只有一个身份证号码,构成了一对一关系;一个班级有多个学生,构成了一对多的关系;课程和学生的关系就构成了多对多的关系,一个学生可以选修多门课程,一门课程对应多个学生。
1.使用Falsk-SQLAlchemy创建一对一的关系表
一对一关系主要在relationship方法中,使用uselist=False来约束,如果查询得到的结果是一个列表,那么久使用uselist=False禁用列表,这样最终查询到的结果就是惟一的,就构成了一对一关系。比如人和身份证的一对一关系,图书管理系统中的学生和借书证的一对一关系,学生和具体借到的某一本书也是一对一关系。
下面以图书管理系统中的用户和借书证构成一对一关系关系为例进行讲解。
主要文件为:
/——config.py
/——app.py
其中config.py文件内容如下:
USER_NAME = 'root' PASSWORD = '104210' HOST = '192.168.112.101' PORT = '3306' DATABASE = 'demo_02' DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8'.format\ (USER_NAME,PASSWORD,HOST,PORT,DATABASE) SQLALCHEMY_DATABASE_URI=DB_URI SQLALCHEMY_TRACK_MODIFICATIONS=False
app.py文件内容如下:
from flask import Flask from flask_sqlalchemy import SQLAlchemy from datetime import datetime import config app = Flask(__name__) app.config.from_object(config) db = SQLAlchemy(app) # 定义用户表 class User(db.Model): __tablename__ = 'user' id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(50), nullable=False) password = db.Column(db.String(50), nullable=False) phone = db.Column(db.String(11), nullable=False) email = db.Column(db.String(30), nullable=False) reg_time = db.Column(db.DateTime, default=datetime.now()) # 定义借书证表 class Lib_card(db.Model): __tablename__ = 'lib_card' id = db.Column(db.Integer, primary_key=True, autoincrement=True) card_id = db.Column(db.Integer, nullable=False) papers_type = db.Column(db.String(50), nullable=False) # 以何种证件办理 borrow_reg_time = db.Column(db.DateTime, default=datetime.now()) # 证件办理时间 user_id = db.Column(db.Integer, db.ForeignKey('user.id')) users = db.relationship('User', backref=db.backref('cards'), uselist=False) db.create_all() @app.route('/add') def add(): #添加三条用户数据 user1 = User(username='张三', password='123456', phone='13888888888', email='1000@flask.com') user2 = User(username='李四', password='234567', phone='13999999999', email='1001@flask.com') user3 = User(username='王五', password='345678', phone='13777777777', email='1002@flask.com') db.session.add(user1) db.session.add(user2) db.session.add(user3) db.session.commit() #添加三条借书证数据 card1 = Lib_card(card_id='18001',user_id='1',papers_type='身份证') card2 = Lib_card(card_id='18002',user_id='2',papers_type='护照') card3 = Lib_card(card_id='18003',user_id='3',papers_type='驾照') db.session.add(card1) db.session.add(card2) db.session.add(card3) db.session.commit() return '数据添加成功!' @app.route('/select') def select(): user = User.query.filter(User.username == '张三').first() art = user.cards for k in art: print(k) print(k.card_id) card = Lib_card.query.filter(Lib_card.card_id == '18001').first() user = card.users print(user.username) return '数据查询成功' if __name__ == '__main__': app.run()
在定义了Lib_card类后,声明了一个外键,并且在relationship方法中使用uselist=False来约束其关系。user_id = db.Column(db.Integer, db.ForeignKey('user.id'))表示创建一个外键,类型要跟主表一样,通过db.ForeignKey('user_id')与主表绑定。users = db.relationship('User', backref=db.backref('cards'), uselist=False)表示user可以根据Lib_card中的借书证查找到用户表中的信息。backref=db.backref('cards')表示用户表可以直接通过cards查找到该用户下的借书证号码。
运行效果如下:
其生成的SQL语句如下:
SELECT lib_card.id AS lib_card_id, lib_card.card_id AS lib_card_card_id, lib_card.papers_type AS lib_card_papers_type, lib_card.borrow_reg_time AS lib_card_borrow_reg_time, lib_card.user_id AS lib_card_user_id FROM lib_card WHERE lib_card.card_id = %(card_id_1)s LIMIT %(param_1)s
2.使用Falsk-SQLAlchemy创建一对多的关系表
生活中典型的一对多关系有哪些?一个年级对应多个平行班级,一个网购用户对应多个订单,一个家庭对应多个家庭成员等,这些是典型的一对多关系。
下面以一个典型的一对多关系为例,即一个作者可以编著多本图书的一对多关系为例,来揭晓flask-sqlalchemy是如何实现一对多关系的。
app.py文件内容如下:
from flask import Flask from flask_sqlalchemy import SQLAlchemy from datetime import datetime import config app = Flask(__name__) app.config.from_object(config) db = SQLAlchemy(app) # 定义作者表 class Writer(db.Model): __tablename__ = 'writer' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(50), nullable=False) books = db.relationship('Book',backref='writers') # 定义书表 class Book(db.Model): __tablename__ = 'books' id = db.Column(db.Integer, primary_key=True, autoincrement=True) title = db.Column(db.String(50), nullable=False) publishing_office = db.Column(db.String(100), nullable=False) isbn = db.Column(db.String(50), nullable=False) writer_id = db.Column(db.Integer, db.ForeignKey('writer.id')) db.create_all() @app.route('/add') def add(): #添加两条作者数据 write1 = Writer(name='雪落长安') write2 = Writer(name='xlca321.cn') db.session.add(write1) db.session.add(write2) db.session.commit() #添加三条书数据 book1 = Book(title='Java开发实战经典',publishing_office='清华大学出版社',isbn='98745685487',writer_id='1') book2 = Book(title='第一行代码', publishing_office='江西农业出版社', isbn='987454875814', writer_id='1') book3 = Book(title='三国演义', publishing_office='历史出版社', isbn='9874565452458', writer_id='2') db.session.add(book1) db.session.add(book2) db.session.add(book3) db.session.commit() return '数据添加成功!' @app.route('/select') def select(): writer = Writer.query.filter(Writer.id == '1').first() art = writer.books for k in art: print(k) print(k.title) book = Book.query.filter(Book.id == '1').first() writer = book.writers print(writer.name) return '数据查询成功' if __name__ == '__main__': app.run()
主要是通过设置外键指向另一方的主键,让作者和图书建立关联关系。通过创建一个外键,类型要与想要关联的表的数据类型一样,这里通过 db.ForeignKey('writer.id')来实现。
运行效果:
3.使用Falsk-SQLAlchemy创建多对多的关系表
生活中典型的多对多关系比较多,一个班级对应多个老师,一个老师对应多个班级。又比如,一个学生对应多门课程,一门课程对应多个学生等,这些都是多对多关系。
下面以一个典型的多对多关系为例进行讲解,即图书和图书标签(上架建议标签)的数据库。很显然,图书可能对应多个标签,不能再使用外键来描述其关系了。同样,也不能在标签表中加入一个指向图书的外键,因为一个标签可以对应着多本图书,两侧都需要一组外键。处理多对多表问题时,解决方法是添加第三张表,这个表成为关联表或中间表。数据库中的多对多关联关系一般需采用中间表的方式处理,将多对多转化为两个一对多。关联表或中间表不要定义成类,在使用db.Table()方法定义时,应该使用两个以上的外键。
app.py文件内容如下:
from flask import Flask from flask_sqlalchemy import SQLAlchemy from datetime import datetime import config app = Flask(__name__) app.config.from_object(config) db = SQLAlchemy(app) book_tag = db.Table('book_tag', db.Column('book_id',db.Integer,db.ForeignKey('book.id'),primary_key=True), db.Column('tag_id',db.Integer,db.ForeignKey('shelfing.id'),primary_key=True) ) class Book(db.Model): __tablename__='book1' id = db.Column(db.Integer,primary_key=True,autoincrement=True) name = db.Column(db.String(50),nullable=False) tags = db.relationship('Shelfing',secondary=book_tag,backref=db.backref('books')) class Shelfing(db.Model): __tablename__ = 'shelfing' id = db.Column(db.Integer,primary_key=True,nullable=False) tag = db.Column(db.String(50),nullable=False) db.create_all() @app.route('/add') def add(): book1 = Book(name = 'Java开发') book2 = Book(name='Python游戏编程快速上手') book3 = Book(name='文艺范') tag1 = Shelfing(tag = '文艺') tag2 = Shelfing(tag = '计算机') tag3 = Shelfing(tag = '技术') book1.tags.append(tag2) book1.tags.append(tag3) book2.tags.append(tag3) book3.tags.append(tag1) db.session.add_all([book1,book2,book3,tag1,tag2,tag3]) db.session.commit() return '数据添加成功!' @app.route('/select') def select(): book = Book.query.filter(Book.name == 'Java开发').first() tag = book.tags for k in tag: print(k.tag) tag = Shelfing.query.filter(Shelfing.tag == '技术').first() book = tag.books for k in book: print(k.name) return '查询成功!' if __name__ == '__main__': app.run()
查询结果如下:
多对多关系仍使用定义一对多关系的db.relationship()方法进行定义。在Book类中,我们使用了tags = db.relationship('Shelfing',secondary=book_tag,backref=db.backref('books'))来定义。db.relationship()一共给出了3个参数;第一个参数Shelfing为多方模型的类名,第二个参数secondary参数设为关联表book_tag;第三个参数backref表示反向引用的名称。假如拿到了一个标签tag,怎么拿到标签下的所有图书呢?这时用books,表示反向引用。多对多关系可以在任何一个类中定义,backref参数会处理好关系的另一侧。关联表就是一个简单的表,不是模型,不要定义为类,SQLAlchemy会自动接管这个表。