2011-05-27 37 views
1

是否可以從另一個表指定鑑別器列?我如何使用聲明來做到這一點?如何正確建模連接的表繼承鑑別符基於SQLAlchemy中的角色

這樣做的原因是我有

class User(Base): 
    id = Column(...) 

class Customer(User): 
    customer_id = Column('id', ...) 

class Mechanic(User): 
    mechanic_id = Column('id', ...) 

class Role(Base): 
    id = Column(..) 

連接表繼承,但想角色的用戶有區別。用戶可以具有買方角色或賣方角色或兩者兼有。

這是模擬此場景的正確方法嗎?

作爲說明,還有買方具體數據和賣方特定數據,這就是爲什麼我使用連接表繼承。

+0

有什麼建議嗎? – sasker 2011-05-27 05:08:43

+0

如果用戶同時擁有「機械師」和「客戶」角色,該怎麼辦? – zzzeek 2011-06-11 18:27:25

回答

3

下面是一個笨拙和低效的方式來實現,具體的結果,如果超過一個角色出現在目標用戶也將失敗:

from sqlalchemy import * 
from sqlalchemy.orm import * 
from sqlalchemy.ext.declarative import declarative_base 

Base = declarative_base() 

role_to_user = Table('role_to_user', Base.metadata, 
    Column('role_id', Integer, ForeignKey('role.id'), primary_key=True), 
    Column('user_id', Integer, ForeignKey('user.id'), primary_key=True), 
) 

class Role(Base): 
    __tablename__ = 'role' 
    id = Column(Integer, primary_key=True) 
    name = Column(String, nullable=False) 

class User(Base): 
    __tablename__ = 'user' 
    id = Column(Integer, primary_key=True) 

    discrim = select([Role.name]) 
    discrim_col = discrim.label("foo") 
    type = column_property(discrim_col) 
    roles = relationship("Role", secondary=role_to_user) 
    __mapper_args__ = {'polymorphic_on': discrim_col} 

User.discrim.append_whereclause(Role.id==role_to_user.c.role_id) 
User.discrim.append_whereclause(role_to_user.c.user_id==User.id) 

class Customer(User): 
    __tablename__ = 'customer' 
    id = Column(Integer, ForeignKey(User.id), primary_key=True) 
    __mapper_args__ = {'polymorphic_identity':'customer'} 

class Mechanic(User): 
    __tablename__ = 'mechanic' 
    id = Column(Integer, ForeignKey(User.id), primary_key=True) 

    __mapper_args__ = {'polymorphic_identity':'mechanic'} 

e = create_engine('sqlite://', echo=True) 

Base.metadata.create_all(e) 

s = Session(e) 

m, c = Role(name='mechanic'), Role(name='customer') 
s.add_all([m, c]) 
s.add_all([Mechanic(roles=[m]), Customer(roles=[c])]) 
s.commit() 

print Session(e).query(User).all() 

接下來,這裏是我會怎麼真正做到這一點,如果我有一個基於零個或多個角色分配行爲的問題 - 我把行爲中的角色,角色的不是車主:

from sqlalchemy import * 
from sqlalchemy.orm import * 
from sqlalchemy.ext.declarative import declarative_base 

Base = declarative_base() 

class User(Base): 
    __tablename__ = 'user' 
    id = Column(Integer, primary_key=True) 
    name = Column(String) 
    roles = relationship("Role", secondary= Table(
        'role_to_user', Base.metadata, 
        Column('role_id', Integer, 
          ForeignKey('role.id'), 
          primary_key=True), 
        Column('user_id', Integer, 
          ForeignKey('user.id'), 
          primary_key=True), 
        ), 
        lazy="subquery" 
       ) 

    def operate_on_roles(self): 
     for role in self.roles: 
      role.operate(self) 

class Role(Base): 
    __tablename__ = 'role' 
    id = Column(Integer, primary_key=True) 
    type = Column(String, nullable=False) 
    __mapper_args__ = {'polymorphic_on': type} 

class CustomerRole(Role): 
    __tablename__ = 'customer' 
    id = Column(Integer, ForeignKey(Role.id), primary_key=True) 
    __mapper_args__ = {'polymorphic_identity':'customer'} 

    def operate(self, user): 
     print "user %s getting my car fixed!" % user.name 

class MechanicRole(Role): 
    __tablename__ = 'mechanic' 
    id = Column(Integer, ForeignKey(Role.id), primary_key=True) 
    __mapper_args__ = {'polymorphic_identity':'mechanic'} 

    def operate(self, user): 
     print "user %s fixing cars!" % user.name 

e = create_engine('sqlite://', echo=True) 

Base.metadata.create_all(e) 

s = Session(e) 

m, c = MechanicRole(), CustomerRole() 
s.add_all([m, c]) 
s.add_all([ 
     User(name='u1', roles=[m, c]), 
     User(name='u2', roles=[c]), 
     User(name='u3', roles=[m]), 
    ]) 
s.commit() 

for user in s.query(User): 
    user.operate_on_roles() 

第二例產生輸出:

user u1 fixing cars! 
user u1 getting my car fixed! 
user u2 getting my car fixed! 
user u3 fixing cars! 

正如你所看到的第二個例子清晰高效,而第一個例子只是一個思想實驗。

1

在最一般的情況下,我會說「不」。

在最一般的情況下,單詞買方賣方不描述角色。他們描述了雙方之間的關係。 (在兩個人之間,在兩個公司之間,或在個人與公司之間)。這種關係取決於一方從另一方購買至少一件東西。

您可能需要買賣雙方的表(記錄用戶表的外鍵)記錄僅與買方相關或僅與賣方相關的細節。但是在沒有任何這種細節的情況下,像{buyer_id,seller_id,product,date_time}這樣的銷售表將成爲記錄誰從誰那裏買了什麼東西的「正常」方式。

+0

我編輯了我的描述,以更具體一點。之前我使用過買方和賣方,因爲我只是想使用一般情況。角色的目的不是描述兩者之間的關係,而是表示訪問應用程序的不同部分。爲了澄清,角色是來自買方/賣方(客戶/機械師)的獨立表/類。買方/賣方類正如您所說的僅僅是專門存儲買方和賣方數據。 – sasker 2011-05-27 19:51:52