2016-07-06 1 views
2

Я использую flask-sqlalchemy с python 2.7.SQLAlchemy гибридное свойство выражение datetime conversion

Я пытаюсь создать свойство, которое я могу использовать в запросе для заказа. Я уже узнал, что должен использовать hybrid_property для этого с соответствующим выражением, но мне трудно получить объект timedelta в выражении.

Запрос Я хочу, чтобы выполнить что-то вроде Article.query.filter(Article.language == language).order_by(Article.popularity.desc())

с

from math import exp 
from datetime import datetime, timedelta 
from sqlalchemy.ext.hybrid import hybrid_property 

class Article(db.Model): 
    __tablename__ = 'articles' 
    article_id = db.Column(db.Integer, primary_key=True) 
    # ... 
    language = db.Column(db.String(64), default='en') 
    date_time = db.Column(db.DateTime, default=datetime.utcnow) 
    readers_frac = db.Column(db.Float, default=0.) 

    @hybrid_property 
    def popularity(self): 
     # compute the popularity based on the readers_frac and the time in minutes since the article was published 
     min_since_published = (datetime.utcnow() - self.date_time).total_seconds()/60. 
     popularity_decay = exp(-(min_since_published**2/(2.*1832.4**2))) 
     return self.readers_frac*popularity_decay 

    @popularity.expression 
    def popularity(cls): 
     # compute the popularity based on the readers_frac and the time in minutes since the article was published 
     min_since_published = (datetime.utcnow() - cls.date_time).seconds/60. 
     popularity_decay = exp(-(min_since_published**2/(2.*1832.4**2))) 
     return cls.readers_frac*popularity_decay 

Однако я получаю ошибку AttributeError: Neither 'BinaryExpression' object nor 'Comparator' object has an attribute 'seconds' при попытке вычислить min_since_published. Любые намеки? Благодаря!!

UPDATE

Я установил ее, изменив все, чтобы sqlalchemy.func выражений, т.е. он работает (с тузд бэкэндом) с

import sqlalchemy as sa 
@popularity.expression 
def popularity(cls): 
    # compute the popularity based on the readers_frac and the time in minutes since the article was published 
    min_since_published = sa.func.timestampdiff(sa.text('MINUTE'), cls.date_time, sa.func.utc_timestamp()) 
    popularity_decay = sa.func.exp(-(sa.func.pow(min_since_published, 2)/6730009.)) 
    return cls.readers_frac*popularity_decay 
+0

В какой базе данных вы используете? (функциональность даты и времени существенно варьируется между ними) – RazerM

+0

Это потому, что 'datetime.utcnow() - cls.date_time' является * выражением SQL * и, следовательно, не имеет' .seconds', в отличие от 'datetime.utcnow() - self. date_time', который является 'datetime'. Вам необходимо найти соответствующую функцию в вашей РСУБД, которая даст вам эквивалентную функциональность. (То же самое с 'exp'.) – univerio

+0

Прямо сейчас я использую SQLite в фоновом режиме, но позже это будет mysql. Я надеялся, что абстракция sqlalchemy не имеет значения ... – cod3licious

ответ

1

Я узнал, что это действительно зависит от базы данных бэкэнда 're using для этого и какие функции он обеспечивает. Например, sqlite не будет работать, поскольку сама база данных просто не имеет возможности отвечать на запрос, но mysql делает это. Тогда на самом деле это просто просмотр того, как функция будет выглядеть как исходный запрос запроса mysql и перевод этого выражения в выражения sqlalchemy.func. Эта работа:

import sqlalchemy as sa 
@popularity.expression 
def popularity(cls): 
    # compute the popularity based on the readers_frac and the time in minutes since the article was published 
    min_since_published = sa.func.timestampdiff(sa.text('MINUTE'), cls.date_time, sa.func.utc_timestamp()) 
    popularity_decay = sa.func.exp(-(sa.func.pow(min_since_published, 2)/6730009.)) 
    return cls.readers_frac*popularity_decay 
Смежные вопросы