【问题标题】:TypeError: sqlalchemy properties -> class 'sqlalchemy.orm.attributes.InstrumentedAttribute'类型错误:sqlalchemy 属性-> 类 'sqlalchemy.orm.attributes.InstrumentedAttribute'
【发布时间】:2018-05-24 12:53:33
【问题描述】:

我有以下sqlalchemy 类(简体):

class Persons(Base):
    __tablename__ = 'm_persons'
    birthDate = db.Column(db.Date, nullable=True)
    @hybrid_property
    def age(self):
        bd = self.birthDate
        return relativedelta(date.today(), bd).years
    @age.expression
    def age(cls):
        bd = cls.birthDate
        return relativedelta(date.today(), bd).years

当我使用该属性将值打印为时

person = Person.query.get(1)
print(person.age)

它正确地打印了人的年龄。现在,当我尝试将该属性用于如下查询时:

Persons.query.filter(Persons.age >= min_age).all()

然后我得到以下错误:

TypeError: relativedelta only diffs datetime/date

我理解为 cls.birthDate 的类型是

class 'sqlalchemy.orm.attributes.InstrumentedAttribute'

那么问题是我缺少什么来获取属性birthDate 的值?

当然,我一直在“谷歌搜索”并阅读了doc,但找不到它不起作用的原因或解决方案。

任何帮助将不胜感激。

*** 编辑 **** 错误的痕迹:

File "/Users/ext334/Dev/python/asocio/app/members/forms.py", line 174, in __init__
    self.person.choices = listPersons(gender=subscription.gender, min_age=subscription.min_age, max_age=subscription.max_age)
  File "/Users/ext334/Dev/python/asocio/app/members/forms.py", line 31, in listPersons
    print(Persons.query.join(Members).filter(Persons.age >= min_age, Persons.age <= max_age, extract('year',Persons.birthDate) >= minBirthYear, extract('year',Persons.birthDate) <= maxBirthYear, Persons.sex == gender).order_by(Members.lastname, Members.firstname))
  File "/Users/ext334/Dev/python/venv36/lib/python3.6/site-packages/sqlalchemy/ext/hybrid.py", line 867, in __get__
    return self._expr_comparator(owner)
  File "/Users/ext334/Dev/python/venv36/lib/python3.6/site-packages/sqlalchemy/ext/hybrid.py", line 1066, in expr_comparator
    owner, self.__name__, self, comparator(owner),
  File "/Users/ext334/Dev/python/venv36/lib/python3.6/site-packages/sqlalchemy/ext/hybrid.py", line 1055, in _expr
    return ExprComparator(cls, expr(cls), self)
  File "/Users/ext334/Dev/python/asocio/app/members/models.py", line 235, in age
    return relativedelta(date.today(), cls.birthDate).years
  File "/Users/ext334/Dev/python/venv36/lib/python3.6/site-packages/dateutil/relativedelta.py", line 102, in __init__
    raise TypeError("relativedelta only diffs datetime/date")
TypeError: relativedelta only diffs datetime/date

完整的查询:

Persons.query.join(Members).filter(Persons.age >= min_age, Persons.age <= max_age, extract('year',Persons.birthDate) >= minBirthYear, extract('year',Persons.birthDate) <= maxBirthYear, Persons.sex == gender).order_by(Members.lastname, Members.firstname)

全班 Persons :

class Persons(Base):
    """
    Description of a person
    """
    __tablename__ = 'm_persons'
    user_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='CASCADE', onupdate='CASCADE'))
    family_id = db.Column(db.Integer, db.ForeignKey('m_families.id', ondelete='CASCADE', onupdate='CASCADE'))

    birthDate = db.Column(db.Date, nullable=True)
    sex = db.Column(db.String(1), nullable=False, default='U') # U = unknown, F = Female, M = Male


    # return the age in years, not rounded

    @hybrid_property
    def age(self):
        return relativedelta(date.today(), self.birthDate).years

    @age.expression
    def age(cls):
        return relativedelta(date.today(), cls.birthDate).years

【问题讨论】:

  • 日期的类型是什么?是 datetime.datetime.date() 或用户定义的东西。您也可以在发出 .all() 之前打印查询以调试原因吗?
  • 日期的类型确实是 datetime.date,所以只是正常的日期不幸的是我无法打印查询,因为它崩溃了,但这里的源 Persons.query.join(Members).filter(Persons.age >= min_age, Persons.age = minBirthYear, extract('year',Persons.birthDate)

标签: python properties flask-sqlalchemy hybrid


【解决方案1】:

好吧,我找到了一种解决方法,或者我更好地理解了它是如何工作的。 在 @age.expression 中,您可以执行数据库的功能。所以我决定根据 MySQL 来计算这个 @age.expression 里面的年龄

这里是代码:

@age.expression
def age(cls):
    return func.year(func.from_days(func.to_days(date.today()) - func.to_days(cls.birthDate)))

基本上,这会计算出生日期和现在之间的年数。所以 flask-sqlalchemy 查询是

Persons.query.join(Members).filter(Persons.age >= min_age, Persons.age <= max_age, extract('year',Persons.birthDate) >= minBirthYear, extract('year',Persons.birthDate) <= maxBirthYear, Persons.sex == gender).order_by(Members.lastname, Members.firstname)

生成的sql语句为:

SELECT m_persons.id AS m_persons_id, m_persons.date_created AS m_persons_date_created, m_persons.date_modified AS m_persons_date_modified, m_persons.user_id AS m_persons_user_id, m_persons.family_id AS m_persons_family_id, m_persons.`birthDate` AS `m_persons_birthDate`, m_persons.sex AS m_persons_sex FROM m_persons INNER JOIN users ON users.id = m_persons.user_id WHERE year(from_days(to_days(%s) - to_days(m_persons.`birthDate`))) >= %s AND year(from_days(to_days(%s) - to_days(m_persons.`birthDate`))) <= %s AND EXTRACT(year FROM m_persons.`birthDate`) >= %s AND EXTRACT(year FROM m_persons.`birthDate`) <= %s AND m_persons.sex = %s ORDER BY users.lastname, users.firstname

因此 @age.expression 返回 year(from_days(to_days(%s) - to_days(m_persons.birthDate))),这在查询中很容易理解

作为总结,我想说的是,在 @age.expression 中,您只能应用数据库函数,而不能真正对列本身进行操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-15
    • 2023-02-10
    • 2020-05-23
    • 1970-01-01
    • 2022-09-23
    • 2013-04-08
    相关资源
    最近更新 更多