Sqlalchemy在时段中获得排名

Cat*_*155 6 python sqlite postgresql sqlalchemy python-3.x

我有一个叫做约会的模型,它的列datetime是一个DateTime字段,duration它是一个Integer字段,代表持续时间,以分钟为单位.现在我要检查,如果func.now()是与datetime任命和的总和datetimeduration

我目前正试图这样做,但我需要一个适用于PostgreSQL和SQLite的解决方案.

current_appointment = Appointment.query.filter(
    Appointment.datetime.between(
        func.now(),
        func.timestampadd(
            'MINUTES', Appointment.duration, func.now()
            )
        )
    ).limit(1).one_or_none()
Run Code Online (Sandbox Code Playgroud)

小智 3

我认为您无法直接在 sqlite 和 postgres 的 ORM 中执行此操作,但 sqlalchemy 允许您使用Custom SQL Constructs 和 Compilation Extension以跨方言的方式扩展它。

这段代码可能并不完全正确,因为我用一些不同的模型对其进行了破解,并将其翻译过来,但我得到了一些非常接近的内容来正确渲染 postgres SQL:

from sqlalchemy import func
from sqlalchemy.sql import expression
from sqlalchemy.types import DateTime
from sqlalchemy.ext.compiler import compiles

class durationnow(expression.FunctionElement):
    type = DateTime()
    name = 'durationnow'

@compiles(durationnow, 'sqlite')
def sl_durationnow(element, compiler, **kw):
    return compiler.process(
        func.timestampadd('MINUTES', element.clauses, func.now())
    )

@compiles(durationnow, 'postgresql')
def pg_durationnow(element, compiler, **kw):
    return compiler.process(
        func.now() + func.make_interval(0, 0, 0, 0, 0, element.clauses)
    )

    # Or alternatively...
    # return "now() - make_interval(0, 0, 0, 0, 0, {})".format(compiler.process(element.clauses))
    # which is more in-line with how the documentation uses 'compiles'
Run Code Online (Sandbox Code Playgroud)

通过类似的设置,您应该能够将原始查询转换为跨方言查询,直接呈现为 SQL,而不是在 Python 中进行持续时间计算:

current_appointment = Appointment.query.filter(
    Appointment.datetime.between(
        func.now(),
        durationnow(Appointment.duration)
    ).limit(1).one_or_none()
Run Code Online (Sandbox Code Playgroud)