簡體   English   中英

Flask SQLalchemy 過濾整數列表

[英]Flask SQLalchemy filter integer list

目前正在嘗試為游戲實現推薦系統,但我在使用 Flask/sqlalchemy 的 REST-API 時遇到了一些問題

我已經成功地實現了檢索游戲和嘗試應用更多過濾器的路線。 我想按流派過濾檢索到的游戲 - 當我按單個流派 id 過濾時會起作用 - 當我嘗試按多個流派過濾時會出現問題。

路線應該看起來像 /games?genres=3,7,8

數據庫有一個游戲和一個流派表,它們之間是一對多的關系,所以一個游戲鏈接到多個流派。

這是游戲 db.Model

game_genres = db.Table('game_genres',
                       db.Column('game_id', db.Integer, db.ForeignKey(
                           'games.id'), primary_key=True),
                       db.Column('genre_id', db.Integer, db.ForeignKey(
                           'genres.id'), primary_key=True),
                       db.PrimaryKeyConstraint('game_id', 'genre_id')
                       )

game_platforms = db.Table('game_platforms',
                          db.Column('game_id', db.Integer, db.ForeignKey(
                              'games.id'), primary_key=True),
                          db.Column('platform_id', db.Integer, db.ForeignKey(
                              'platforms.id'), primary_key=True),
                          db.PrimaryKeyConstraint('game_id', 'platform_id')
                          )

class Game(db.Model):
    __tablename__ = 'games'

    id = db.Column(db.Integer, unique=True, primary_key=True)
    title = db.Column(db.String, nullable=False)
    description = db.Column(db.String)
    year = db.Column(db.Integer)
    genres = db.relationship(
        'Genre',
        secondary=game_genres,
        lazy='subquery',
        backref=db.backref('genres', lazy=True, cascade='all, delete')
    )
    platforms = db.relationship(
        'Platform',
        secondary=game_platforms,
        lazy='subquery',
        backref=db.backref('games', lazy=True, cascade='all, delete')
    )

    def __init__(self, title: str):
        self.title = title

    def __repr__(self):
        return f'<Game {self.title}>'

    @property
    def to_json(self):
        genres = []
        for genre in self.genres:
            genres.append(genre.to_json)
        platforms = []
        for platform in self.platforms:
            platforms.append(platform.to_json)
        return {
            'id': self.id,
            'title': self.title,
            'description': self.description,
            'year': self.year,
            'genres': genres,
            'platforms': platforms,
        }
    @classmethod
    def return_all(self, offset, limit):
        return {'games': [g.to_json for g in self.query.order_by(Game.id).offset(offset).limit(limit).all()]}

    @classmethod
    def return_bygenres(self, offset, limit, genres2):
        return {'games': [g.to_json for g in self.query\
                         .join(Game.genres, aliased=True)\
                         .filter(or_(*[id.like(gid)for gid in genres2])).all().order_by(Game.id).offset(offset).limit(limit).all()]}


這是相應的流派模型

class Genre(db.Model):
    __tablename__ = "genres"

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)

    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return f'<Genre {self.name}>'

    @property
    def to_json(self):
        return {
            'id': self.id,
            'name': self.name,
        }

路線看起來像這樣

GAME_PARSER = reqparse.RequestParser()
GAME_PARSER.add_argument('offset', type=int)
GAME_PARSER.add_argument('limit', type=int)
GAME_PARSER.add_argument('genres')


class AllGames(Resource):
    def get(self):
        args = GAME_PARSER.parse_args()
        offset = 0 if args.offset is None else args.offset
        limit = 100 if args.limit is None else args.limit
        genres = args.genres
        return Game.return_bygenres(offset, limit, genres.split(","))

我在另一篇文章中找到了當前查詢,但它引發了錯誤。 我得到的錯誤是“'buildtin_function_or_method'對象沒有屬性'like'”

我嘗試過其他不同的方法,例如使用 any、has 或 in function,但它們都返回上述錯誤。

使用self.query.join(Game.genres, aliased=True).filter_by(id==1).order_by(Game.id).offset(offset).limit(limit).all()只返回游戲有流派 ID 1

我不確定我是否在查詢中犯了錯誤,或者模型沒有為那種查詢正確實現。

這是我第一次使用 Flask 和 sqlalchemy 進行編碼,所以我將不勝感激任何形式的輸入!

方法filterfilter_by采用不同類型的參數。 請參閱此問題/答案“SQLAlchemy 中 filter 和 filter_by 之間的差異”以獲取解釋。

由於您的Genre id字段是一個整數,我將使用in_運算符來過濾此字段。 例如

@classmethod
def return_bygenres(self, offset, limit, genres2):
    # genres2 must be a list of integers, coerce if neccassary, e.g.
    # .filter(Genre.id.in_([int(s) for s in genres2]))

    _query = self.query\
            .join(Game.genres, aliased=True)\
            .filter(Genre.id.in_(genres2))\
            .order_by(Game.id)\
            .offset(offset)\
            .limit(limit)\
    return {'games': [g.to_json for g in _query.all()]}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM