classes表格
classID | className | location | leader | remark |
---|---|---|---|---|
21 | 快乐花朵班 | 101 | 小明 | |
22 | 幸福宝宝班 | 102 | 花花 | |
23 | 国际宝宝班 | 102 | jack | |
24 | 艺术兴趣班 | 103 | tony |
students表格
st_id | name | gender | age | cls_id | remark |
---|---|---|---|---|---|
10001 | 小明 | 1 | 18 | 21 | 小明是位可爱的孩子 |
10002 | 小红 | 0 | 18 | 22 | 小红是位聪明的孩子 |
10003 | 大牛 | 1 | 19 | 21 | 大牛是位勇敢的孩子 |
10004 | 花花 | 0 | 17 | 22 | 花花是位懂事的孩子 |
10005 | tony | 1 | 20 | 23 | tony来自美国 |
10006 | 古天乐 | 1 | 22 | 21 | 黑马王子 |
10007 | 陈道明 | 1 | 23 | 22 | 不是所有牛奶都叫特仑苏 |
# db_module文件
from APP import db
class Classes(db.Model):
__tablename__ = "classes"
classID = db.Column(db.INT, primary_key=True, autoincrement=True)
className = db.Column(db.Text)
location = db.Column(db.Text)
leader = db.Column(db.Text)
remark = db.Column(db.Text)
# 在此申明Classes类与Students类具备指向关系,且具体的关联是通过外键db.ForeignKey这个绑定的
class_relate_student = db.relationship("Students", backref='student_relate_class', lazy='dynamic')
class Students(db.Model):
__tablename__ = "students"
st_id = db.Column(db.INT, primary_key=True, autoincrement=True)
name = db.Column(db.Text)
gender = db.Column(db.Text)
age = db.Column(db.INT)
remark = db.Column(db.Text)
# 指定classID这个字段来源于classes表格的外键,指向方式:表名 + 字段名(表名)
cls_id = db.Column(db.Integer, db.ForeignKey("classes.classID"))
key = "花花"
stu = Students.query.filter_by(name=key).first()
clsName = stu.student_relate_class.className # stu.student_relate_class 会跳转到 classes 表
print(clsName)
class_relate_student 描述了:Students和Classes的关系
- 第一个参数:为对应参照的类名"Students"
- 第二个参数:backref为类Students申明新的属性(这个属性方便在2个表格之间互相指向)
- 第三个参数:lazy决定了什么时候SQLALchemy从数据库中加载数据
lazy对应的详细解释,可参考:
https://blog.csdn.net/bestallen/article/details/52601457
https://blog.csdn.net/jiulixiang_88/article/details/80587071
customer表格
id | name | work |
---|---|---|
1 | 程老板 | 大兴有限公司 |
2 | 李老板 | 弘成科技 |
3 | 司马老板 | 小马加油有限公司 |
product表格
id | name | price |
---|---|---|
1 | 丝绸 | 35 |
2 | 铝合金 | 54 |
3 | 盐 | 3 |
association表格
id | customer_id | product_id |
---|---|---|
1 | 1 | 1 |
2 | 1 | 2 |
3 | 1 | 3 |
4 | 2 | 2 |
5 | 3 | 2 |
6 | 3 | 3 |
在多对多的关系中,如何根据某个产品名,查询到哪些人购买了这个产品呢?
from flask_sqlalchemy import SQLAlchemy
from APP.app import app
db = SQLAlchemy(app)
association_table = db.Table('association',
db.Column('id', db.Integer, primary_key=True, autoincrement=True),
db.Column('customer_id', db.Integer, db.ForeignKey('customer.id')),
db.Column('product_id', db.Integer, db.ForeignKey('product.id'))
)
class Customer(db.Model):
__tablename__ = 'customer'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(10))
work = db.Column(db.String(20))
def __repr__(self):
return 'name:{name} work:{work}'.format(name=self.name, work=self.work)
customer_to_product = db.relationship('Product',
secondary=association_table,
backref='product_to_customer',
lazy='dynamic'
)
class Product(db.Model):
__tablename__ = 'product'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(10))
price = db.Column(db.Float)
def __repr__(self):
return 'name:{name} price:{price}'.format(name=self.name, price=self.price)
key = '盐'
pro = Product.query.filter_by(name=key).first()
print(pro, type(pro))
c = pro.product_to_customer
print(c, type(c))
for i in c:
print(i.name, i.work)
最终输出:
name:盐 price:3.0 <class '__main__.Product'>
[name:程老板 work:大兴有限公司, name:司马老板 work:小马加油有限公司] <class 'sqlalchemy.orm.collections.InstrumentedList'>
程老板 大兴有限公司
司马老板 小马加油有限公司
同理,通过查询某个人的信息,找到这个人购买了哪些产品?
key = '司马老板'
ct = Customer.query.filter_by(name=key).first()
print(ct, type(ct))
p = ct.customer_to_product
print(p, type(p))
for i in p:
print(i.name, i.price)
name:司马老板 work:小马加油有限公司 <class '__main__.Customer'>
SELECT product.id AS product_id, product.name AS product_name, product.price AS product_price
FROM product, association
WHERE %(param_1)s = association.customer_id AND product.id = association.product_id <class 'sqlalchemy.orm.dynamic.AppenderBaseQuery'>
铝合金 54.0
盐 3.0
CREATE TABLE `association` (
`id` int(2) NOT NULL AUTO_INCREMENT COMMENT 'id',
`customer_id` int(2) NOT NULL COMMENT '客户号',
`product_id` int(2) NOT NULL COMMENT '产品编号',
PRIMARY KEY (`id`,`customer_id`,`product_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
- 如上表格里面,三个字段都为主键。
- 其实id字段不需要也可以,但是一定要声明另外2个字段为主键。目的是方便通过2个主键,关联两张表格。
- 且这2个主键也分别是另外两张表格的主键。
association_table = db.Table('association',
db.Column('id', db.Integer, primary_key=True, autoincrement=True),
db.Column('customer_id', db.Integer, db.ForeignKey('customer.id')),
db.Column('product_id', db.Integer, db.ForeignKey('product.id'))
)
- 如上的数据库模型类,比另外两个特殊的地方在于,他是在association表格的基础上,再重新定义2个字段的外键,且重新定义了字段的名称。
- flask_sqlalchemy把旧的表格association,定义为新的association_table表格去使用
- 定义了customer_id的字段,来源于外键customer.id(表名+字段)
- 定义了product_id的字段,来源于外键product.id(表名+字段)
customer_to_product = db.relationship('Product',
secondary=association_table,
backref='product_to_customer',
lazy='dynamic'
)
- 这两张表格的主键已经通过association_table表格关联。
- db.relationship这个方法,主要是关联2个表格的对象之间的关系
- 使用backref这个参数,可以理解为是一种虚拟的指向关系,从一个对象指向到另一个对象的中间枢纽。
- 第一个参数:当前类需要关联的----新类名
- 第二个参数:secondary,这个是重新定义的关联表
- 第三个参数:新类名指向当前类名的中间枢纽名
- lazy:这个是加载表格的方式
参考知识:
https://www.jianshu.com/p/92890a4ec0cb
https://www.cnblogs.com/chichung/p/9794850.html