模型内部的Flask SQLAlchemy查询功能

时间:2019-09-08 14:05:35

标签: python sqlalchemy flask-sqlalchemy

我有一个这样的模型:

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    first_name = db.Column(db.String(64), index=True)
    last_name = db.Column(db.String(64), index=True)

    def full_name(self):
        return '%s %s' % (self.first_name, self.last_name)

我想在查询中获得full_name方法,我尝试这样:

user = db.session.query(User.full_name()).all()

但是我收到此错误消息:

TypeError: full_name() missing 1 required positional argument: 'self'

然后我尝试调用不带括号的函数:

user = db.session.query(User.full_name).all()

然后我收到此错误消息:

sqlalchemy.exc.InvalidRequestError: SQL expression, column, or mapped entity expected - got '<function User.full_name at 0x7f265960aae8>'

那么,在用户模型中查询full_name()方法的正确方法是什么??

2 个答案:

答案 0 :(得分:4)

您需要创建两个hybrid attributes。一个在实例上定义full_name的属性,一个在类上定义full_name(用于查询)并且取决于该属性的表达式。

这是纯sqlalchemy,但是hybrid属性在flask-sqlalchemy中应该相同。

import sqlalchemy as sa
from sqlalchemy.ext import hybrid

class User(Base):
    __tablename__ = 'users' 

    id = sa.Column(sa.Integer, primary_key=True)
    first_name = sa.Column(sa.String)
    last_name = sa.Column(sa.String)

    @hybrid.hybrid_property
    def full_name(self):  
        return '%s %s' % (self.first_name, self.last_name)

    @full_name.expression
    def full_name(self): 
        return self.first_name + ' ' + self.last_name


users = session.query(User).filter_by(full_name='Joan Doe').all()

编辑: 正如Ilja所言,在这种情况下,一种方法就足够了:

class User(Base):
    ...

    @hybrid.hybrid_property
    def full_name(self):  
        return self.first_name + ' ' + self.last_name

之所以可行,是因为sqlalchemy将+ operator映射到数据库的CONCAT函数,因此不需要表达式装饰器。

答案 1 :(得分:1)

您可以使用@classmethod

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    first_name = db.Column(db.String(64), index=True)
    last_name = db.Column(db.String(64), index=True)

    @classmethod
    def full_name_filter(cls, fname, lname):
        return (cls.first_name == fname, cls.last_name == lname)

然后

user = db.session.query(User).filter(*User.full_name_filter("first", "last")).all()