【问题标题】:Sqlalchemy filter by calculated datetime hybrid_propertySqlalchemy 过滤器按计算的日期时间 hybrid_property
【发布时间】:2019-05-29 18:55:21
【问题描述】:

我有一个模型处方。

from datetime import timedelta
from sqlalchemy.ext.hybrid import hybrid_property


class Prescription(db.Model):
    """ docstring """
    ID = db.column(db.Integer, primary_key=True)
    date = db.Column(db.DateTime)
    duration = db.Column(db.SmallInteger)

    @hybrid_property
    def expiration_date(self):
        # return self.date + timedelta(days=self.duration)
        return self.date + timedelta(days=7)

    @classmethod
    def actual(cls ):
        """ docstring """
        today = datetime.today()

        return cls.query.filter(Prescription.expiration_date>=today)

我只想在我的实际方法中获得实际处方,并且当我指定时

@hybrid_property
def expiration_date(self): 
    return self.date + timedelta(days=7)

一切都像魅力一样。

但每个处方都有不同的持续时间,而且我指定的时间

@hybrid_property
def expiration_date(self): 
     return self.date + timedelta(days=self.duration)

我有一个错误

TypeError: unsupported type for timedelta days component: InstrumentedAttribute

我试着做一个这样的小技巧

@property
def days(self):
    return int(self.duration)

但没有运气。 谁能告诉一些解决方法,或者为持续时间字段创建一些惰性对象,或者以其他方式获得实际处方,通过计算的 expire_date 过滤?

【问题讨论】:

  • 你用的是什么数据库?
  • PostgreSQL 和包 psycopg2-binary==2.7.7

标签: python-3.x sqlalchemy flask-sqlalchemy


【解决方案1】:

您可能正在尝试计算 DATEDIFF: Calculate DATEDIFF in POSTGRES using SQLAlchemy

这里,is_expired 将生成一个 SQL 查询部分,计算开始日期和utcnow() 之间的天数差,并将结果与​​self.duration 进行比较

这适用于 PostgreSQL,但我还没有在其他 RDBMS 上测试过。

from datetime import datetime
import sqlalchemy as sa


class Prescription:
    ID = db.column(db.Integer, primary_key=True)
    date = db.Column(db.DateTime)
    duration = db.Column(db.SmallInteger)

    @hybrid_property
    def is_expired(self):
        days_since_published = sa.func.trunc((
            sa.extract('epoch', datetime.utcnow()) -
            sa.extract('epoch', self.date)
        ) / 3600 / 24)

        return days_since_published >= self.duration

    @classmethod
    def active(cls):
        return cls.query.filter(is_expired=False)

【讨论】:

    【解决方案2】:

    在您的 @classmethod 注释 actual() 方法中,您尝试访问引发错误的非静态属性(expiration_date)。 根据我对您的代码在做什么的理解,我已将代码更改如下:

    from datetime import datetime,timedelta
    from sqlalchemy.ext.hybrid import hybrid_property
    from flask_sqlalchemy import SQLAlchemy
    from flask import Flask
    
    app = Flask(__name__)
    db = SQLAlchemy(app)
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
    app.config['SQLALCHEMY_DATABASE_URI'] ='sqlite:///'
    
    class Prescription(db.Model):
        """ docstring """
        def mydefault(context):
            return context.get_current_parameters()['date'] + timedelta(days=context.get_current_parameters()['duration'])
    
        ID = db.Column(db.Integer,primary_key= True)
        date = db.Column(db.Date)
        duration = db.Column(db.SmallInteger)
        expiration_date = db.Column(db.Date,default = mydefault)
    
        @classmethod
        def actual(cls ):
            """ docstring """
            today = datetime.today().date()
            return cls.query.filter(Prescription.expiration_date>=today).all()
        def __repr__(self):
          return "Id:{} , date:{}, duration:{}, expiration_date:{}".format(self.ID,self.date,self.duration,self.expiration_date)
    
    db.create_all()
    q=Prescription(ID=1,date=datetime(2019,5,26).date(),duration = 1) #Expired
    r=Prescription(ID=2,date=datetime(2019,5,20).date(),duration = 3) #Expired
    s=Prescription(ID=3,date=datetime(2019,5,27).date(),duration = 5) #Not Expired
    t = Prescription(ID=4,date=datetime.now().date(),duration = 1) #Not Expired
    
    db.session.add(q)
    db.session.add(r)
    db.session.add(s)
    db.session.add(t)
    db.session.commit()
    
    list_obj = Prescription.query.all()
    print("All Objects in DB:-")
    for l in list_obj:
      print(l)
    print()
    print("Valid Prescription:")
    print(Prescription.actual())
    

    输出:

    我可以向您建议的一件事是,模型不需要到期时间。 所以你可以改变

    date = db.Column(db.DateTime)
    

    date = db.Column(db.Date)
    

    它会减轻你的任务:)

    【讨论】:

    • 请尝试查询Prescription.actual(),因为查询后出现错误。
    • 在这种情况下,actual 是一个类方法。如果你想比较其中某物的属性。你也需要传递对象。不是吗?
    • 是的,它是一个类方法,但是我需要为每个对象计算expiration_date,所以在查询调用时会运行属性的比较。
    • 你能在你正在使用的地方添加一些代码,以便我清楚地理解它
    • 只需创建一些具有不同日期时间的处方对象并尝试获取实际。例如。 Prescription(ID=1,date=datetime(2019,5,26),duration = 1) Prescription(ID=2,date=datetime(2019,5,20),duration = 3) Prescription(ID=3,date=datetime(2019,5,27),duration = 5) Prescription.actual()
    猜你喜欢
    • 2017-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多