sqlalchemy列是带有绑定参数的sql表达式

时间:2016-06-22 01:01:23

标签: sqlalchemy flask-sqlalchemy

我正在尝试映射一个具有列的类,该类实际上并不存在,但它只是一个在查询时获取绑定参数的sql表达式。下面的模型是我正在尝试做的一个例子。

class House(db.Model):
    __tablename__ = 'houses'

    id = db.Column(db.Integer, primary_key=True)

    @hybrid_property
    def distance_from_current_location(self):
        # what to return here?
        return self.distance_from_current_location

    @distance_from_current_location.expression
    def distance_from_current_location(cls, latitude, longitude):
        return db.func.earth_distance(
            db.func.ll_to_earth(latitude, longitude), cls.earth_location)

    # defer loading, as the raw value is pretty useless in python
    earth_location = deferred(db.Column(EARTH))

然后我想通过flask-sqlalchemy查询:

latidude = 80.20393
longitude = -90.44380

paged_data = \
    House.query \
         .bindparams({'latitude': latitude, 'longitude': longitude}) \
         .paginate(1, 20, False)

我的问题是:

  1. 我该怎么做?是否可以使用这样的hybrid_property?
  2. 如果我可以使用hybrid_property,python方法应该返回什么? (没有python方式来解释它,它应该只返回DB表达式返回的任何内容。
  3. 纬度和经度仅在查询时间内存在,需要为每个查询绑定。如何在查询时间内绑定纬度和经度?我编写的代码片段中的bindparams位,但它说明了我想要做的事情。是否可以这样做?
  4. 我已经阅读了文档,但在示例中找不到任何带有bind参数的hybrid_property或方法......

    (另外,因为这不是一个真正的专栏,而是我想在我的模型上使用的东西,我不希望这会触发alembic为它生成一个新列。)

    谢谢!

1 个答案:

答案 0 :(得分:0)

你不能这样做。 distance_from_current_location也不是假列,因为它取决于查询特定的参数。想象一下,你要为此写一个SQL视图;你会怎么写这个定义? (提示:你不能。)

SQLAlchemy使用标识映射模式,这意味着对于特定主键,整个会话中只存在一个实例。您将如何处理查询相同的实例但具有不同的纬度/经度值? (从后面的查询返回的实例将覆盖从前一个查询返回的实例。)

执行此操作的正确方法是在查询时通过其他实体,如下所示:

House.query \
     .with_entities(House, db.func.earth_distance(db.func.ll_to_earth(latitude, longitude), House.earth_location)) \
     .filter(...)

或通过hyrbid_method(其使用情况需要每次都传入latitudelongitude):

class House(db.Model):
    ...
    @hybrid_method
    def distance_from_current_location(self, latitude, longitude):
        # implement db.func.ll_to_earth(latitude, longitude), self.earth_location) **in Python** here

    @distance_from_current_location.expression
    def distance_from_current_location(cls, latitude, longitude):
        ...