使用SQLAlchemy创建去重数据库模式 - 如何用ORM语义表示一个组?
我正在尝试用MySQL创建一个简单的实体去重方案,并使用SQLAlchemy来进行编程访问。
我想实现一个特定的效果,我觉得这有点像自引用查询,但我不太确定:
基本上,我有一个“entities”表(里面有唯一的entity_id),还有一个相关的Entity对象,然后有一个entity_groups表(为了简单起见),它有“group_id”和“entity_id”这两列,这样我就可以通过为这个关系创建一行来“注册”一个实体到一个组。这个表也和一个ORM对象关联 - EntityGroup。
我的问题是,如何让EntityGroup对象引用组中的所有实体呢?
我想我需要写一些类似这样的代码:
mapper(EntityGroup, entity_groups_table, properties={ 'entities': relationship( Entity, .... ? ) },
但我对细节有点模糊。基本上,我需要获取entity_groups中所有与对象表示的那一行具有相同group_id的行。然后,我需要提取所有与这些行的entity_id列相关的Entity对象。这听起来像是可以通过SQLAlchemy中更详细的Query()操作来实现,但我不确定如何将其与relationship()构造结合起来(如果可以的话 - 也许手动处理?)
任何帮助都将非常有用,希望我说得清楚明了。
1 个回答
你真的不应该使用Query
来做这件事,因为如果你正确配置了关系,系统会自动处理这些。假设你只用entity_group
表来存储关系,而没有其他用途,你只需要按照文档中的说明配置多对多关系就可以了。下面是一个完整的示例,应该能帮助你理解:
from sqlalchemy import create_engine, Column, Integer, String, MetaData, ForeignKey, Table
from sqlalchemy.orm import relationship, mapper, scoped_session, sessionmaker, backref
from sqlalchemy.ext.associationproxy import association_proxy
# Configure test DB
engine = create_engine(u'sqlite:///:memory:', echo=False)
session = scoped_session(sessionmaker(bind=engine, autoflush=False))
metadata = MetaData()
# tables
entities_table = Table('entities', metadata,
Column('entity_id', Integer, primary_key=True),
)
groups_table = Table('groups', metadata,
Column('group_id', Integer, primary_key=True),
)
entity_groups_table = Table('entity_groups', metadata,
Column('entity_id', Integer, ForeignKey('entities.entity_id'), primary_key=True),
Column('group_id', Integer, ForeignKey('groups.group_id'), primary_key=True),
)
# object model
class Group(object):
def __repr__(self): return "<Group: %d>" % (self.group_id,)
class Entity(object):
def __repr__(self): return "<Entity: %d>" % (self.entity_id,)
# mappers
mapper(Group, groups_table)
mapper(Entity, entities_table,
properties={'groups': relationship(Group, secondary=entity_groups_table, backref='entities')},
)
# create db schema
metadata.create_all(engine)
# == TESTS
# create entities
e1 = Entity()
e2 = Entity()
g1 = Group()
g2 = Group()
g3 = Group()
g1.entities.append(e1)
g2.entities.append(e2)
g3.entities.append(e1)
g3.entities.append(e2)
session.add(e1)
session.add(e2)
session.commit()
# query...
session.expunge_all()
# check Peter
for g in session.query(Group).all():
print "group: ", g, " has ", g.entities
这段代码应该会产生类似这样的结果:
group: <Group: 1> has [<Entity: 1>]
group: <Group: 2> has [<Entity: 1>, <Entity: 2>]
group: <Group: 3> has [<Entity: 2>]