2012-10-16 102 views
4
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 

我很困惑如何設置ID和與SQLAlchemy中的子類的關係(我碰巧使用Flask-SQLAlchemy)。我的一般設計是讓超類Pin是具有地理定位的任何東西的高級表示(即用戶,地點等)。SQLAlchemy子類/繼承關係

Pin和Geolocation對象之間存在一對一的關係,因此地理位置不同時包含兩個用戶(或用戶和地點)的位置。現在我想要繼承Pin來創建User類。一個用戶對象應該有一個名字password_hash,鹽,我也希望能夠通過userObj.geolocation查找用戶的地理位置。不過,我後來想要創建一個班級,這也是Pin的子類,我應該能夠通過placeObj.geolocation查找地點的地理位置。給定一個地理定位對象,我應該可以使用geolocationObj.pin來查找用戶/地點/等。該地理位置對象對應於。我介紹超類別Pin的全部原因是爲了確保Pin和Geolocation對象之間存在純粹的一對一關係,而不是將Geolocation與要求地理位置表具有user_idplace_id的用戶或人關聯列,其中一個將始終爲空。

我期待每個用戶都可以通過引用Geolocation的父Pin類自動擁有.geolocation屬性,但它看起來像SQLAlchemy沒有這樣做。我如何使子類關係工作來實現我的目標:讓用戶和地點以及潛在其他類的子類Pin,每個類都具有通過Pin的地理位置屬性,並且在Pin和地理位置之間具有一對一的關係?

回答

6

我想出的解決方案。這充當了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) 
4

以下是SQLAlchemy中mapping inheritance hierarchiesdoing it declaratively的文檔。

我相信你會想要連接表繼承的味道,這意味着你的父類鏈中的每個類都有自己的表,其中只有它獨有的列。基本上,您需要在pin表中添加一個鑑別器列來表示每個Pin的子類類型,以及一些用於描述SQLAlchemy的繼承配置的類的雙下劃線屬性。

+6

這就是爲什麼只有鏈接的答案是垃圾 –