如何在SQLAlchemy(ORM)中对3个表的多对多关系进行建模?

时间:2012-04-03 15:00:19

标签: python sql orm sqlalchemy

我在SQL中生锈,对SQL Alchemy来说是全新的,但是有一个即将推出的项目同时使用它们。所以我觉得我写点东西让自己感到舒服。遇到宿醉,我决定写一些东西来追踪酒精含量。

events users 参与并消费 drinks 。这是我的三个基本表(带有一个帮助表guestlist,用于用户事件之间的m:n关系。)

饮料始终将所有活动上的饮料列入所有用户(无需映射任何内容)。 用户会不时创建,事件也是如此。所有用户都可以加入所有事件,因此我使用guestlist表来映射这些事件。

现在问题的核心:我需要跟踪用户在哪个时间消耗哪种饮料。我尝试用另一个表shots解决这个问题(见下文),但我不确定这是否是一个很好的解决方案。

ERP Diagram http://s1.anyimg.com/img/g6ld1ku/Bildschirmfoto.png

SQL Alchemy中它可能看起来有点像这样(或者不是,但这是我到目前为止所提出的)::

guestlist_table = Table('guestlist', Base.metadata,
    Column('event_id', Integer, ForeignKey('events.id')),
    Column('user_id', Integer, ForeignKey('users.id'))
)

class Event(Base):

  __tablename__ = 'events'

  id = Column(Integer, primary_key=True)
  name = Column(String(80), nullable=False)
  started = Column(DateTime, nullable=False, index=True,
    default=datetime.datetime.now
  )
  users = relationship("User", secondary=guestlist_table, backref="events")
  # ...

class User(Base):

  __tablename__ = 'users'

  id = Column(Integer, primary_key=True)
  name = Column(String(50), nullable=False, unique=True, index=True)
  birthdate = Column(Date, nullable=False)
  weight = Column(Integer, nullable=False)
  sex = Column(Boolean, nullable=False)
  # ...

class Drink(Base):

  __tablename__ = 'drinks'

  id = Column(Integer, primary_key=True)
  name = Column(String(50), nullable=False)
  volume = Column(Numeric(5,2), nullable=False)
  percent = Column(Numeric(5,2), nullable=False)
  # ...

class Shots(Base):

  __tablename__ = 'shots'

  id = Column(Integer, primary_key=True)
  at = Column(DateTime, nullable=False,
    default=datetime.datetime.now
  )
  user_id = Column(Integer, ForeignKey('users.id'), index=True)
  event_id = Column(Integer, ForeignKey('events.id'), index=True) 
  drink_id = Column(Integer, ForeignKey('drinks.id'))
  user = relationship("User", backref="shots")
  event = relationship("Event", backref="shots")
  drink = relationship("Drink", uselist=False) # one-to-one, no backref needed

我很难找到一种方法来构建一个将事件用户饮料映射到一起的表格:我应该如何制定relationships以及我如何query

事情是我有点觉得我忽略了一些东西。 坦率地说,我绝对迷失于如何查询它?

以下是我大部分时间都会进行的查询:

  • 我至少需要获得一个事件所消耗的所有镜头(可能按用户排序)
  • 我有时也需要特定用户的所有镜头(可能按事件排序)
  • 还有很多计算:
    • 每个赛事的投篮次数
    • 每位用户的拍摄数量
    • 用户在某个活动中失败的投篮次数

shots表是否可以管理它?

1 个答案:

答案 0 :(得分:5)

我建议你绘制一个实体关系图,让人们和你理解你的问题会更清楚。

回答你的问题:

  

我至少需要在事件中消耗所有镜头(可能按用户排序)

要获取活动的所有镜头,您可以尝试

session.query(Shots).filter_by(event_id=event_id)

event_id是您要查询的事件的ID。要按用户存储,您可以尝试

from sqlalchemy.sql.expression import desc, asc
session.query(Shots) \
    .filter_by(event_id=event_id) \
    .order_by(asc(Shots.user_id))

当然,您可能希望按用户的属性排序,您可以加入用户表。

from sqlalchemy.sql.expression import desc, asc
session.query(Shots) \
    .filter_by(event_id=event_id) \
    .join(User) \
    .order_by(asc(User.name))

很容易。

  

我有时也需要特定用户的所有镜头(可能按事件排序)

就像之前的例子一样

  

每个赛事的投篮次数

session.query(Shots) \
    .filter_by(event_id=event_id) \
    .count()

我没有运行它们,我只是在这里写了它们,但是如果我没有写错字,它们都应该可以工作。