![](/img/trans.png)
[英]Flask-SQLAlchemy,How to sort results in Many-to-Many Relationship?
[英]Flask-SqlAlchemy Many-To-Many relationship with duplicates allowed
我有一个Order - FoodItem
多对多关系,如下所示:
association_table = db.Table('association', db.Model.metadata,
db.Column('left_id', db.Integer, db.ForeignKey('orders.order_id')),
db.Column('right_id', db.Integer, db.ForeignKey('fooditems.fooditem_id'))
)
class OrderModel(ReviewableModel):
__tablename__ = 'orders'
order_id = db.Column(db.Integer, db.ForeignKey('reviewables.id'), primary_key=True)
food_items = db.relationship("FoodItemModel", secondary = association_table)
__mapper_args__ = {'polymorphic_identity':'orders'}
class FoodItemModel(ReviewableModel):
__tablename__ = 'fooditems'
fooditem_id = db.Column(db.Integer, db.ForeignKey('reviewables.id'), primary_key=True)
__mapper_args__ = {'polymorphic_identity':'fooditems'}
用户可以请求具有重复foodItem的订单。 这是正确创建的,但是当我将更改保存到数据库时,将删除重复项。 例如,我点3个比萨饼:
def save_to_db(self):
print('before: '+str(self.food_items))
db.session.add(self)
db.session.commit()
print('after: '+str(self.food_items))
输出是这样的:
before: [<FoodItemModel u'Pizza'>, <FoodItemModel u'Pizza'>, <FoodItemModel u'Pizza'>]
after: [<FoodItemModel u'Pizza'>]
关联表已正确更新:
"left_id" "right_id"
"6" "3"
"6" "3"
"6" "3"
但是,OrderModel中的food_items只包含1个项目
Juan Mellado在他的回答中得到的是关系数据(RD)和对象关系映射(ORM)冲突:ORM无法区分具有相同数据的单独对象。 要解决此问题,只需将一个id
列作为主键添加到association_table
- 这样ORM就可以区分具有相同left_id
和right_id
不同记录。
但这将是一种解决方法,而不是解决方案。
解决方案是考虑“用户可以请求具有重复foodItems的订单”时的含义。 从订单到食品的关系不是直接的,它是通过订单项间接的。 每个订单商品属于订单(其又属于顾客或餐桌),并且每个订单商品可以与食品相关。 通过使每个订单项唯一,“重复食品”的问题消失。 同时,我们现在可以通过向每个订单商品添加可选的“客户请求”来获得无限量的食品变化。 例如“食物:薯条,要求:容易上盐”。
在代码中的示例下,客户“我尖叫”放置1份订单,其中3份“冰淇淋”,其中1份“洒在上面”。
from sqlalchemy import Column, Integer, String, ForeignKey, create_engine
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.pool import StaticPool
Base = declarative_base()
class Order(Base):
__tablename__ = 'order'
id = Column(Integer, primary_key=True)
customer = Column(String(127))
items = relationship("OrderItem")
def __repr__(self):
return "<Order(id='{}', customer='{}', items='{}')>".format(self.id, self.customer, self.items)
class Food(Base):
__tablename__ = 'food'
id = Column(Integer, primary_key=True)
name = Column(String(127))
def __repr__(self):
return "<Food(id='{}', name='{}')>".format(self.id, self.name)
class OrderItem(Base):
__tablename__ = 'order_item'
id = Column(Integer, primary_key=True)
order_id = Column(Integer, ForeignKey(Order.id))
order = relationship(Order)
food_id = Column(Integer, ForeignKey(Food.id))
food = relationship(Food)
comment = Column(String(127))
def __repr__(self):
return "<OrderItem(id='{}', order_id='{}', food_id='{}, comment={}')>" \
.format(self.id, self.order_id, self.food_id, self.comment)
def orderFood():
engine = create_engine('sqlite:///:memory:', echo=True, connect_args={'check_same_thread':False}, poolclass=StaticPool)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
food = Food(name='ice cream')
session.add(food)
order = Order(customer='I scream')
session.add(order)
session.commit()
print("Food: {}".format(food))
print("Order: {}".format(order))
order.items = [OrderItem(order=order, food=food), OrderItem(order=order, food=food), \
OrderItem(order=order, food=food, comment='with sprinkles on top')]
session.merge(order)
session.commit()
print("Order: {}".format(order))
print("Order.items")
for item in order.items:
print(item)
print("OrderItems for order")
orderFilter = OrderItem.order_id == order.id
for order_item in session.query(OrderItem).filter(orderFilter).all():
print(order_item)
print("Food in order")
for row in session.query(Food).join(OrderItem).filter(orderFilter).all():
print(row)
session.close();
if __name__ == "__main__":
orderFood()
您必须为关联表声明主键。
Flask-SQLALchemy是一个ORM,它需要一系列唯一标识行的列。
看看这部分文档,有点过时,但仍然有效: http : //docs.sqlalchemy.org/en/rel_1_1/faq/ormconfiguration.html#faq-mapper-primary-key
Flask-SQLALchemy使用所有字段(left_id,right_id)来标识行,并且所有行都具有相同的值(6,3)。 因此,所有行都存储在数据库中(因为没有任何声明的约束),但只有一行保留在上下文(内存)中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.