6
class Geolocation(db.Model):
    __tablename__ = "geolocation"
    id = db.Column(db.Integer, primary_key=True)
    latitude = db.Column(db.Float)
    longitude = db.Column(db.Float)
    elevation = db.Column(db.Float)         # Meters
    # Relationships
    pin = db.relationship('Pin', uselist=False, backref="geolocation")

    def __init__(self, latitude, longitude, elevation):
        self.latitude = latitude
        self.longitude = longitude
        self.elevation = elevation

    def __repr__(self):
        return '<Geolocation %s, %s>' % (self.latitude, self.longitude)


class Pin(db.Model):
    __tablename__ = "pin"
    id = db.Column(db.Integer, primary_key=True)
    geolocation_id = db.Column(db.Integer, db.ForeignKey('geolocation.id'))  # True one to one relationship (Implicit child)

    def __init__(self, geolocation_id):
        self.geolocation_id = geolocation_id

    def __repr__(self):
        return '<Pin Object %s>' % id(self)      # Instance id merely useful to differentiate instances.


class User(Pin):
    #id = db.Column(db.Integer, primary_key=True)
    pin_id = db.Column(db.Integer, db.ForeignKey('pin.id'), primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password_hash = db.Column(db.String(120), nullable=False)
    salt = db.Column(db.String(120), nullable=False)
    # Relationships
    #posts = db.relationship('Post', backref=db.backref('user'), lazy='dynamic')               #One User to many Postings.

    def __init__(self, username, password_hash, salt, geolocation_id):
        super(Pin, self).__init__(self, geolocation_id)
        self.username = username
        self.password_hash = password_hash
        self.salt = salt

    def __repr__(self):
        return '<User %r>' % self.username

SQLAlchemyでIDとサブクラスとの関係を設定する方法について混乱しています(たまたまFlask-SQLAlchemyを使用しています)。私の一般的な設計は、スーパークラスのピンをジオロケーションを持つもの(つまり、ユーザー、場所など)の高レベルの表現にすることです。

PinオブジェクトとGeolocationオブジェクトの間には1対1の関係があるため、Geolocationには、たとえば2人のユーザー(またはユーザーと場所)の場所が同時に含まれることはありません。次に、Pinをサブクラス化してUserクラスを作成します。Userオブジェクトには、名前、password_hash、saltが必要です。また、を介してユーザーのジオロケーションを検索できるようにする必要がありますuserObj.geolocation。ただし、後でPinをサブクラス化するクラスPlaceを作成したいので、を介してPlaceのジオロケーションを検索できるようにする必要がありますplaceObj.geolocation。ジオロケーションオブジェクトが与えられれば、私は使用できるはずですgeolocationObj.pinユーザー/場所などを検索します。ジオロケーションオブジェクトが対応する。user_id私がスーパークラスのPinを導入した理由は、Geolocationテーブルにplace_id列が必要なUserまたはPersonにGeolocationを関連付けるのではなく、PinオブジェクトとGeolocationオブジェクトの間に純粋な1対1の関係があることを確認するためでした。そのうちの1つは常にnullになります。

ジオロケーションを参照する親Pinクラスを介して、すべてのユーザーが自動的に.geolocationプロパティを持つことを期待していましたが、SQLAlchemyはこれを行わないようです。User and Placeと潜在的に他のクラスにPinをサブクラス化し、それらの各クラスにPinを介したジオロケーションプロパティを持たせ、PinとGeolocationの間に1対1の関係を持たせるという目標を達成するために、サブクラス化関係を機能させるにはどうすればよいですか?

4

2 に答える 2

7

私が思いついた解決策。これは、SQLAlchemyで宣言型スタイルでサブクラス化し、Join継承を使用する完全な例として機能します。

class Geolocation(Base):
    __tablename__ = "geolocation"
    id = Column(Integer, primary_key=True)
    latitude = Column(Float)
    longitude = Column(Float)
    elevation = Column(Float)         # Meters
    # Relationships
    person = relationship('Pin', uselist=False, backref="geolocation")

    def __init__(self, latitude, longitude, elevation):
        self.latitude = latitude
        self.longitude = longitude
        self.elevation = elevation

    def __repr__(self):
        return '<Geolocation %s, %s>' % (self.latitude, self.longitude)


class Pin(Base):
    __tablename__ = 'pin'
    id = Column(Integer, primary_key=True)
    geolocation_id = Column(Integer, ForeignKey('geolocation.id'), unique=True, nullable=False)  # True one to one relationship (Implicit child)
    type = Column('type', String(50))              # discriminator
    __mapper_args__ = {'polymorphic_on': type}

    def __init__(self, geolocation_id):
        self.geolocation_id = geolocation_id


class User(Pin):
    __tablename__ = 'user'
    id = Column(Integer, ForeignKey('pin.id'), primary_key=True)
    __mapper_args__ = {'polymorphic_identity': 'user',
                       'inherit_condition': (id == Pin.id)}
    user_id = Column(Integer, autoincrement=True, primary_key=True, unique=True)
    username = Column(String(80), unique=True)
    password_hash = Column(String(120))
    salt = Column(String(120))
    posts = relationship('Posting', primaryjoin="(User.user_id==Posting.user_id)", backref=backref('user'), lazy='dynamic')   #One User to many Postings.

    def __init__(self, username, password_hash, salt, geo_id):
        super(User, self).__init__(geo_id)
        self.username = username
        self.password_hash = password_hash
        self.salt = salt

    def __repr__(self):
        return '<User %s>' % (self.username)


class Posting(Pin):
    __tablename__ = 'posting'
    id = Column(Integer, ForeignKey('pin.id'), primary_key=True)
    __mapper_args__ = {'polymorphic_identity': 'posting',
                        'inherit_condition': (id == Pin.id)}
    posting_id = Column(Integer, autoincrement=True, primary_key=True, unique=True)
    creation_time = Column(DateTime)
    expiration_time = Column(DateTime)
    user_id = Column(Integer, ForeignKey('user.user_id'))              # One User to many Postings

    def __init__(self, creation_time, expiration_time, user_id, geo_id):
        super(Posting, self).__init__(geo_id)
        # For now, require creation time to be passed in. May make this default to current time.
        self.creation_time = creation_time
        self.expiration_time = expiration_time
        self.user_id = user_id

    def __repr__(self):
        #TODO come up with a better representation
        return '<Post %s>' % (self.creation_time)
于 2012-10-17T17:37:58.837 に答える
3

継承階層をマッピングし、SQLAlchemyで宣言的に行うためのドキュメントは次のとおりです。

結合されたテーブル継承フレーバーが必要になると思います。つまり、親クラスチェーン内のすべてのクラスには、固有の列を持つ独自のテーブルがあります。pin基本的に、各ピンのサブクラスタイプを示すためにディスクリミネーター列をテーブルに追加し、SQLAlchemyへの継承構成を説明するためにクラスにいくつかの二重アンダースコアプロパティを追加する必要があります。

于 2012-10-16T21:52:17.730 に答える