我尝试使用Postgresql数据库使用Flask和SQLAlchemy创建后端。在models.py中设置架构时,我有一个Card对象和一个Color对象。有五种颜色,每张卡可以有多种颜色。因此,我尝试使用与Association Object,ColorAssociation的多对多关系。相关的models.py代码如下:
class ColorAssociation(db.Model):
__tablename__ = 'color_association'
card_id = db.Column(db.Integer, db.ForeignKey('cards.id'), primary_key=True)
color_id = db.Column(db.Integer, db.ForeignKey('colors.id'), primary_key=True)
card = db.relationship("Card", back_populates="colors")
color = db.relationship("Color", back_populates="cards")
class Color(db.Model):
__tablename__ = 'colors'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String())
cards = db.relationship("ColorAssociation", back_populates="color")
class Card(db.Model):
__tablename__ = 'cards'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String())
colors = db.relationship("ColorAssociation", back_populates="card")
在添加一些数据之后,架构似乎正常运行,我可以成功查询与颜色相关联的所有卡片,并使用名称' Blue'例如,通过使用以下sqlalchemy查询:
blue = db.session.query(Color).filter(Color.name == 'Blue').all()[0]
for association in blue.cards:
print(association.card)
我的问题是如何查询多种颜色的卡片?例如,我如何查询所有与颜色相关的卡片,并且名称为' Blue'和'格林'。
答案 0 :(得分:0)
所以我重新创建了一个测试环境并尝试复制你所遇到的问题,这里常见的缺陷是sqlalchemy在后台提供了一些繁重的工作。由于您将关联放在必须连接到表的另一个模型中,因此在逻辑稍微复杂时会查询。因此,例如,您希望所有蓝色或红色的卡片都是一个衬垫db.session.query(Color).filter(or_(color='blue',color='red'))).all()
。
但是既然你要求卡片都有这两种颜色,我们需要获得所有独特的卡片并添加其各自的颜色。从那里我们过滤我们想要的颜色(在这种情况下是蓝色和红色)。然后确保每张卡具有我们想要的相同数量的颜色。这是通过使用具有功能来实现的。以下示例。
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import random
from sqlalchemy import and_, func, or_
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
class ColorAssociation(db.Model):
__tablename__ = 'color_association'
card_id = db.Column(db.Integer, db.ForeignKey(
'cards.id'), primary_key=True)
color_id = db.Column(db.Integer, db.ForeignKey(
'colors.id'), primary_key=True)
card = db.relationship("Card", back_populates="colors")
color = db.relationship("Color", back_populates="cards")
class Color(db.Model):
__tablename__ = 'colors'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String())
cards = db.relationship("ColorAssociation", back_populates="color")
def __repr__(self):
return "< %d, %s>" % (self.id, self.name)
class Card(db.Model):
__tablename__ = 'cards'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String())
colors = db.relationship("ColorAssociation", back_populates="card")
db.create_all()
colors_avail = ['blue', 'red', 'green', 'orange', 'pink']
for x in colors_avail:
col = Color(name=x)
db.session.add(col)
db.session.commit()
for x in range(0, 20):
card = Card(name=str(x) + "card")
db.session.add(card)
db.session.commit()
colors_id = []
for randnum in range(1, 6):
rand = random.randint(1, 5)
if not rand in colors_id:
colors_id.append(rand)
for color_id in colors_id:
association = ColorAssociation(card_id=card.id, color_id=color_id)
db.session.add(association)
db.session.commit()
# Get color ids these are unique in this case
colors = db.session.query(Color).filter(
or_(Color.name == 'blue', Color.name == 'red')).all()
# Create array of these ids
colors_ids = [color.id for color in colors]
cards = db.session.query(Card).distinct(Card.id).outerjoin(ColorAssociation). \
filter(ColorAssociation.color_id.in_(colors_ids)).group_by(Card.id).having(
func.count(ColorAssociation.color_id) == len(colors_ids)).all()
"""
This doesn't work
cards = db.session.query(ColorAssociation). \
filter(ColorAssociation.color_id.in_(colors_ids)).group_by(ColorAssociation.color_id).having(
func.count(ColorAssociation.color_id) == len(colors_ids)).all()
"""
for card in cards:
print(card)