簡體   English   中英

Postgres用作SQLAlchemy中的列

[英]Postgres function as column in SQLAlchemy

我在Postgesql數據庫中有兩個功能:

  • id_generator ,它從時間戳生成id
  • timestamp_from_id(id) ,將id轉換為timestamp

假設這是我的模型:

class DatModel(object):
    id = Column(
        BigInteger,
        primary_key=True,
        server_default=text('id_generator()')
    )
    name = Column(String(50), index=True)

我想要做的就是通過查詢timestamp所產生timestamp_from_id(id)功能,例如:

dbsession.query(DatModel).filter(DatModel.timestamp > datetime.now()).all()

要么

obj = dbsession.query(DatModel).first()
created = obj.timestamp

我的問題是:

如何基於postgres函數創建虛擬列?

提前致謝


編輯:

不滿意的方法#1

正如Roman Dryndik所 建議的那樣,可能的解決方案是使用func 它是一種工作方法,但是在檢索時間戳時幾乎沒有問題:

timestamp = session.execute(func.timestamp_from_id(obj.id)).fetchone()

我更喜歡這樣做:

timestamp = obj.timestamp

不滿意的方法2

第二種可能的解決方案是使用編譯擴展

from datetime import datetime

from sqlalchemy import DateTime
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.functions import FunctionElement

class Timestamp(FunctionElement):
    type = DateTime()
    name = 'timestamp'

@compiles(Timestamp)
def default_timestamp(element, compiler, **kw):
    return compiler.visit_function(element)

@compiles(Timestamp, 'postgresql')
def pg_created(element, compiler, **kw):
    arg1 = list(element.clauses)[0]
    return 'timestamp_from_id({})'.format(compiler.process(arg1))


# filter example
obj = session.query(DatModel).filter(Timestamp < datetime.now()).first()

# get timestamp attribute example
timestamp = session.execute(Timestamp(obj.id)).fetchone()

請閱讀“ SQL表達式用作列屬性”文檔的column_property部分。

使用它,您應該能夠:

class DatModel(Base):
    id = Column(
        Integer,
        primary_key=True,
        server_default=text('id_generator()')
    )
    name = Column(String(50), index=True)

    timestamp = column_property(func.timestamp_from_id(id))

timestamp也將包含在查詢中,您可以在過濾和/或排序表達式中使用它:

q = (session.query(DatModel)
     .filter(DatModel.timestamp > datetime.now())
     .order_by(DatModel.timestamp.desc())
    )

如果我正確理解了您的問題,則可以使用func調用存儲過程timestamp_from_id

因此,您將獲得如下內容:

from sqlalchemy import func

# some code here

dbsession.query(DatModel).filter(func.timestamp_from_id(DataModel.id) > datetime.now()).all()

# some code here

沒有嘗試代碼。 也許您也應該執行func.timestamp_from_id(DataModel.id).scalar()

您可以在這里這里找到更多信息。

解決方案是使用hybrid_propertyexpressiondocs

class DatModel(Base)::
    id = Column(
        BigInteger,
        primary_key=True,
        server_default=text('id_generator()')
    )

    @hybrid_property
    def timestamp(self):
        return object_session(self). \
            scalar(select([func.timestamp_from_id(self.id)]))

    @created.expression
    def timestamp(self):
        return func.timestamp_from_id(self.id)

用法示例:

obj = DatModel()
with transaction.manager:
    session.add(obj)
obj = session.query(DatModel).one()

assert type(obj.timestamp) == datetime.datetime
assert obj.timestamp.date() == datetime.date.today()


objs = session.query(DatModel) \
    .filter(DatModel.timestamp < datetime.datetime.now())
assert objs.count() == 1

objs = session.query(Gateway) \
    .filter(DatModel.timestamp > datetime.datetime.now())
assert objs.count() == 0

你可以使用一個實現這一column_propertyliteral_column 例如:

class DatModel(object):
    id = Column(
        BigInteger,
        primary_key=True,
        server_default=text('id_generator()')
    )
    name = Column(String(50), index=True)
    timestamp = column_property(literal_column("timestamp_from_id(datmodel.id)", type_=DateTime).label('timestamp'))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM