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成为具有地理定位的任何东西的高级表示(即用户,地点等)。
Pin和Geolocation对象之间存在一对一的关系,因此Geolocation不会同时包含两个用户(或用户和地点)的位置。现在我想子类Pin来创建User类。 User对象应该有一个名称,password_hash,salt,我也希望能够通过userObj.geolocation
查找用户的地理位置。但是,我后来想要创建一个类Place,它也是Pin的子类,我应该能够通过placeObj.geolocation
查找Place的地理位置。给定地理定位对象,我应该能够使用geolocationObj.pin
来查找用户/地点/等。地理定位对象对应的。我引入超类Pin的全部原因是为了确保Pin和Geolocation对象之间存在纯粹的一对一关系,而不是让Geolocation与User或Person相关联,这需要Geolocation表具有{{1 }和user_id
列,其中一列始终为null。
我希望每个用户都可以通过父Pin类自动拥有place_id
属性,该类引用了一个地理位置,但似乎SQLAlchemy不会这样做。如何使子类关系工作以实现我的目标,即具有User和Place以及可能的其他类子类Pin,让每个类通过Pin具有地理定位属性,并且在Pin和Geolocation之间具有一对一的关系? / p>
答案 0 :(得分:7)
我提出的解决方案。这是在声明式样式中使用Join继承在SQLAlchemy中进行子类化的完整示例。
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)
答案 1 :(得分:3)
以下是SQLAlchemy中mapping inheritance hierarchies和doing it declaratively的文档。
我相信你会想要连接表继承的味道,这意味着你父类链中的每个类都有自己的表,其中包含唯一的列。基本上,您需要在pin
表中添加一个discriminator列来表示每个Pin的子类类型,并为您的类添加一些双下划线属性来描述SQLAlchemy的继承配置。