2017-02-17 14 views
1

私はSQLAlchemyのORMを初めて使用しました。私は、データベーステーブルを持っているLabelPosition、およびDataSet次のように:SQLAlchemyで2つのモデルクラスを結合する方法

enter image description here

そして、次の対応するPythonのクラス:

class Label(Base): 
    __tablename__ = 'Label' 

    id = Column(Integer, primary_key=True) 
    name = Column(String, nullable=False, unique=true) 


class Position(Base): 
    __tablename__ = 'Position' 

    id = Column(Integer, primary_key=True) 
    name = Column(String, nullable=False, unique=true) 


class DataSet(Base): 
    __tablename__ = 'DataSet' 

    id = Column(Integer, primary_key=True) 
    label_id = Column(Integer, ForeignKey('Label.id')) 
    position_id = Column(Integer, ForeignKey('Position.id')) 
    timestamp = Column(Integer, nullable=False) 

しかし、私のservieで、私はそれらのlabel_idを公開していないとし、 position_id。だから私は新しいクラスDataを文字列としてlabelpositionを保持するようにしました。

# Not a full class to only show my concept 
class Data: 
    # data dictionary will have data 
    def __init__(self, **kwargs): 
     # So it doesn't have ids. Label and Position as string 
     keys = {'label', 'position', 'timestamp'} 
     self.data = {k: kwargs[k] for k in keys} 

    # An example of inserting data. 
    # skipped detail and error handling to clarify 
    def insert(self): 
     session = Session() 
     # get id of label and position 
     # remember that it returns a tuple, not a single value 
     self.data['label_id'] = session.query(Label.id).\ 
      filter(Label.name == self.data['label']).one_or_none() 
     self.data['position_id'] = session.query(Position.id).\ 
      filter(Position.name == self.data['position']).one_or_none() 
     # add new dataset 
     self.data.pop('label') 
     self.data.pop('position') 
     new_data = DataSet(**self.data) 
     session.add(new_data) 
     session.commit() 

しかし、それはやや醜いように見えますが、私はそれを行う簡単な方法があると思います。 SQLAlchemy APIを使用してこれらのテーブルクラスを組み合わせる方法はありますか?

答えて

1

あなたはLabelDataSetPositionオブジェクトからリンクを作成するrelationshipsassociation proxiesを使用することができます。この後

from sqlalchemy.orm import relationship 
from sqlalchemy.ext.associationproxy import association_proxy 

class DataSet(Base): 
    __tablename__ = 'DataSet' 

    id = Column(Integer, primary_key=True) 

    label_id = Column(Integer, ForeignKey('Label.id')) 
    label = relationship('Label') 
    label_name = association_proxy('label', 'name') 

    position_id = Column(Integer, ForeignKey('Position.id')) 
    position = relationship('Position') 
    position_name = association_proxy('position', 'name') 

    timestamp = Column(Integer, nullable=False) 

を使用すると、新しい属性を通じてDataSet(およびそれらの名前)にリンクされているLabelPositionオブジェクトにアクセスすることができます

>>> d = session.query(DataSet).first() 
>>> d.position 
<Position object at 0x7f3021a9ed30> 
>>> d.position_name 
'position1' 

DataSetのオブジェクトはそうではありません残念なことに美しい。あなたは新しいDataSetオブジェクトを作成することができ、このように両方のプロキシにcreator機能を指定した後

def _label_creator(name): 
    session = Session() 
    label = session.query(Label).filter_by(name=name).first() 
    if not label: 
     label = Label(name=name) 
     session.add(label) 
     session.commit() 
    session.close() 
    return label 

label_name = association_proxy('label', 'name', creator=_label_creator) 

:あなたは名前を得ることができたassociation_proxyためcreator関数を指定して作成するか、または(this answerで見つかった)対応するオブジェクトを取得することができ

dataset = DataSet(
    label_name='label1', 
    position_name='position2', 
    timestamp=datetime.datetime.now() 
) 
+0

私は関係について読んだことがありますが、関連プロキシについてはわかりませんでした。これは私の時間を節約します。どうもありがとうございました! –

関連する問題