我正在使用sqlalchemy,也使用alembic进行迁移(和flask-sqlalchemy)。我有一个使用EARTH数据类型的postgres表。
CREATE TABLE things
(
id INTEGER PRIMARY KEY NOT NULL,
name TEXT,
earth_location EARTH
)
Run Code Online (Sandbox Code Playgroud)
这是我的sqlalchemy映射:
class Thing(db.Model):
__tablename__ = 'things'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.UnicodeText, nullable=False)
earth_location = db.Column(???)
Run Code Online (Sandbox Code Playgroud)
如何映射接地柱?
Alembic迁移能够应付吗?
谢谢!
可以通过以下方式使用earth来自Earthdistance扩展的类型列与SQLAlchemy:
column_property,如果您只想将纬度和经度值映射到属性UserDefinedType,如果您希望使用完整类型,例如支持创建表A的column_property实现有些直接,但仅限于只读,如果声明列不可用,则需要一些非正统的语法:
from sqlalchemy import Float, column, func
from sqlalchemy.orm import column_property
class Thing(db.Model):
__tablename__ = 'things'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.UnicodeText, nullable=False)
_earth_location = column('earth_location', _selectable=Thing.__table__)
Thing.earth_location_latitude = column_property(func.latitude(
_earth_location, type_=Float))
Thing.earth_location_longitude = column_property(func.longitude(
_earth_location, type_=Float))
Run Code Online (Sandbox Code Playgroud)
为了产生column具有正确的_selectable的属性Thing,必须在创建类之后将其添加到类中,因为Table在类主体中创建时声明式创建的内容不可用。这样就可以查询
session.query(Thing.earth_location_longitude).scalar()
Run Code Online (Sandbox Code Playgroud)
按预期工作。没有_selectable,发出的SQL将是:
SELECT longitude(loc)
Run Code Online (Sandbox Code Playgroud)
不幸的是,这使映射表完全忽略了基础列things.earth_location,因此Alembic也不是更明智的选择。Alembic中的表创建必须通过执行原始SQL字符串来完成。
A UserDefinedType具有能够支持表创建的优点。原始earth值是在Python方面没什么用,所以一些来回ll_to_earth,latitude而且longitude是必需的功能。将a UserDefinedType与a 结合使用column_property可能会提供“两全其美”的解决方案:
from sqlalchemy.types import UserDefinedType
from sqlalchemy.orm import deferred
class EARTH(UserDefinedType):
def get_col_spec(self, **kw):
return 'EARTH'
class Thing(db.Model)
__tablename__ = 'things'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.UnicodeText, nullable=False)
# defer loading, as the raw value is pretty useless in python
earth_location = deferred(db.Column(EARTH))
# A deferred column, aka column_property cannot be adapted, extract the
# real column. A bit of an ugly hack.
latitude = column_property(func.latitude(*earth_location.columns,
type_=Float))
longitude = column_property(func.longitude(*earth_location.columns,
type_=Float))
Run Code Online (Sandbox Code Playgroud)
检查表创建:
In [21]: t = Table('test', meta, Column('loc', EARTH))
In [22]: print(CreateTable(t))
CREATE TABLE test (
loc earth
)
Run Code Online (Sandbox Code Playgroud)
添加一个新的Thing:
>>> latitude = 65.012089
>>> longitude = 25.465077
>>> t = Thing(name='some name',
earth_location=func.ll_to_earth(latitude, longitude))
>>> session.add(t)
>>> session.commit()
Run Code Online (Sandbox Code Playgroud)
请注意,提供了对的绑定函数调用ll_to_earth作为值。
支持将lat和lon作为属性等访问的更复杂的自定义类型是完全可能的,但可能超出此q / a的范围。
| 归档时间: |
|
| 查看次数: |
359 次 |
| 最近记录: |