[英]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 進行編碼,所以我將不勝感激任何形式的輸入!
方法filter
和filter_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.