У меня есть рецепт модели.
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
В вашем @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
является методом класса. если вы хотите сравнить атрибуты чего-то в нем. вам также нужно передать объект. не так ли?
да, это метод класса, но мне нужно вычислить expire_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()
Когда вызывается Prescription.actual()
. В своем коде он использует Prescription.expiration_date
, который зависит от объекта, поэтому он принимает self
в качестве аргумента. Как вы будете удовлетворять его зависимость.
упс, ты прав. Я думаю, что решением в моем случае может быть добавление дополнительного столбца expiration_date
, а затем запрос по нему. Большое спасибо.
Конечно, нет проблем. Всего наилучшего :)
Определенно да.
Можете ли вы проголосовать и принять ответ, если это было полезно. Так что это помогает всем, кто посещает ваш вопрос. Хорошего дня.
Возможно, вы пытаетесь вычислить DATEDIFF: Вычислить DATEDIFF в POSTGRES, используя SQLAlchemy
Здесь is_expired
сгенерирует часть запроса SQL, которая вычисляет разницу в днях между датой начала и utcnow()
и сравнивает результат с self.duration
Это работает в PostgreSQL, но я не тестировал другие СУБД.
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)
какую базу данных вы используете?