#python #sqlite #sqlalchemy
#python #sqlite #sqlalchemy
Вопрос:
Я пытаюсь настроить гибридное свойство SQLAlchemy для декларативного отображаемого класса a Person
, у которого есть вызываемое DateTime
поле birth_date
, представляющее дату рождения человека.
Я хочу настроить a @hybrid_property
, который будет представлять возраст человека, например:
class Person(Base):
__tablename__ = 'person'
name: str = Column(String)
date_of_birth: DateTime = Column(DateTime)
#works fine after the objects are loaded
@hybrid_property
def age(self):
today = date.today()
if self.date_of_birth:
return today.year - self.date_of_birth.year - (
(today.month, today.day) < (self.date_of_birth.month, self.date_of_birth.day))
@age.expression
def age(cls): #Don't know how to set this up
pass
У меня возникли проблемы с настройкой expression
для гибридного свойства. Насколько я понимаю, выражение должно возвращать оператор SQL, который помог бы фильтровать / запрашивать базу данных для возраста preson.
С этой целью работает следующий SQL
SELECT (strftime('%Y', 'now') - strftime('%Y', person.date_of_birth)) - (strftime('%m-%d', 'now') < strftime('%m-%d', person.date_of_birth)) as age from person
Но я не знаю, как «указать» выражению использовать этот SQL (или даже если это правильный способ сделать это.) Я пытался использовать текст следующим образом:
@age.expression
def age(cls):
current_time = datetime.utcnow()
return text(f"{current_time.year} - strftime('%Y', '{cls.date_of_birth}')")
Но это не сработало. Я не знаю, как указать выражению использовать оператор SQL в качестве выбора для виртуального столбца. (Это будет столбец age)
Цель состоит в том, чтобы иметь возможность фильтровать и запрашивать age
свойство следующим образом:
session.query(Person).filter(Person.age > 25)
Пожалуйста, окажите помощь.
Ответ №1:
Эта часть гибридного свойства должна возвращать исполняемое предложение SQLAlchemy. И поскольку в Postgres уже есть подходящая функция для этого, вы можете просто использовать ее:
import sqlalchemy as sa
@age.expression
def age(cls):
return sa.func.age(cls.date_of_birth)
Функция: документы, ищите age(timestamp)
.
Или в MySQL:
@age.expression
def age(cls):
return sa.func.timestampdiff('year', cls.date_of_birth, sa.func.curdate())
Или в SQLite:
@age.expression
def age(cls):
strftime = sa.func.strftime
year_diff = strftime('%Y', 'now') - strftime('%Y', cls.date_of_birth)
# If the month and date of the current year are before the
# month and date of birth, then we need to subtract one year
# because the "birthday" hasn't happened yet.
is_partial_year = strftime('%m-%d', 'now') < strftime('%m-%d', cls.date_of_birth)
return year_diff - is_partial_year
Комментарии:
1. Спасибо, что помогли мне! Не могли бы вы пояснить, что
<
означает оператор в этом контексте? Я имею в виду, еслиis_partial_year
вычисляетсяtrue
, то оно подстраиваетis_partial_year
? Итакis_partial_year
, логическое значение, которое принимает значение либо1
или0
, а затем происходит вычитание?2. Да, точно, логическое значение по сути является целым числом 1/0 и обрабатывается здесь так. Это справедливо как для кода SQL, так и для кода Python