Ошибка типа: свойства sqlalchemy -> класс 'sqlalchemy.orm.attributes.InstrumentedAttribute' - PullRequest
0 голосов
/ 24 мая 2018

У меня есть следующий класс 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 но не смог найти причину, по которой она не работает или решение.

Любая помощь будет оценена.

*** EDIT **** След ошибки:

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)

Полный класс Персоналов:

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

1 Ответ

0 голосов
/ 24 мая 2018

Ну, я нашел обходной путь или, может быть, я лучше понял, как это работает.В @age.expression вы можете выполнять функции вашей базы данных.Поэтому я решил рассчитать возраст внутри этого @age.expression на основе MySQL

Вот код:

@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 вы можете только применять функцию базы данных и не работать с самим столбцом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...