2016-07-06 83 views
2

我正在用python 2.7使用flask-sqlalchemy。SQLAlchemy混合属性表达式日期时间转换

我试图创建一个属性,我可以在查询中使用来排序。我已经了解到我应该使用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 

但是试图计算min_since_published时,我发现了错误AttributeError: Neither 'BinaryExpression' object nor 'Comparator' object has an attribute 'seconds'。任何提示?谢谢!!

UPDATE

我固定它通过改变一切sqlalchemy.func表达式,即它的工作原理(与MySQL后端)与

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表达式*,因此不像'datetime.utcnow() - self那样具有'.seconds'。 date_time',这是'datetime'。您需要在您的RDBMS中找到相应的功能,以提供相应的功能。 (与'exp'一样的东西。) – univerio

+0

现在我在后台使用SQLite,但后来它将成为mysql。我希望sqlalchemy抽象这不会有问题... – cod3licious

回答

1

我学到它实际上取决于后端数据库您'正在使用它以及它提供的功能。例如,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