РЕДАКТИРОВАТЬ: Это очень похоже на SqlAlchemy - фильтрация по атрибуту отношения в том, что мы оба пытаемся фильтровать по атрибутам отношения.Тем не менее, они фильтруют на соответствие точному значению, в то время как я фильтрую с использованием подобно / содержит.Из-за этого, как указано в комментариях, мое решение требует дополнительного шага, который не был очевиден в другом посте.
Позвольте мне предвосхитить это следующим образом: я все еще довольно плохо знаком с SQLAlchemy, так что он полностьюВозможно, я поступаю об этом совершенно неправильно.
У меня есть Flask API, который определил «оповещения» и «события».Предупреждение может принадлежать только одному событию, а событие может иметь несколько предупреждений.Схема для предупреждений следующая:
class Alert(PaginatedAPIMixin, db.Model):
__tablename__ = 'alert'
id = db.Column(db.Integer, primary_key=True, nullable=False)
type = db.relationship('AlertType')
type_id = db.Column(db.Integer, db.ForeignKey('alert_type.id'), nullable=False)
url = db.Column(db.String(512), unique=True, nullable=False)
event_id = db.Column(db.Integer, db.ForeignKey('event.id'), nullable=False)
event = db.relationship('Event')
def __str__(self):
return str(self.url)
def to_dict(self):
return {'id': self.id,
'event': self.event.name,
'type': self.type.value,
'url': self.url}
Одна из конечных точек API позволяет получить список предупреждений на основе различных критериев фильтрации.Например, получить все оповещения о alert_type X или все оповещения с X внутри своего alert_url.Однако единственное, что меня озадачивает, - это то, что я хочу иметь возможность получать все оповещения с символом X в названии связанных с ними событий.
Вот функция конечной точки API (бит закомментированных событий является моей первоначальной «наивностью»«подход, который не работает из-за того, что событие является связью), но вы можете понять, что я пытаюсь сделать с фильтрацией.
def read_alerts():
""" Gets a list of all the alerts. """
filters = set()
# Event filter
#if 'event' in request.args:
# filters.add(Alert.event.name.like('%{}%'.format(request.args.get('event'))))
# URL filter
if 'url' in request.args:
filters.add(Alert.url.like('%{}%'.format(request.args.get('url'))))
# Type filter
if 'type' in request.args:
type_ = AlertType.query.filter_by(value=request.args.get('type')).first()
if type_:
type_id = type_.id
else:
type_id = -1
filters.add(Alert.type_id == type_id)
data = Alert.to_collection_dict(Alert.query.filter(*filters), 'api.read_alerts', **request.args)
return jsonify(data)
Набор фильтров, который создается, подается вФункция to_collection_dict (), которая по существу возвращает разбитый на страницы список запроса со всеми фильтрами.
def to_collection_dict(query, endpoint, **kwargs):
""" Returns a paginated dictionary of a query. """
# Create a copy of the request arguments so that we can modify them.
args = kwargs.copy()
# Read the page and per_page values or use the defaults.
page = int(args.get('page', 1))
per_page = min(int(args.get('per_page', 10)), 100)
# Now that we have the page and per_page values, remove them
# from the arguments so that the url_for function does not
# receive duplicates of them.
try:
del args['page']
except KeyError:
pass
try:
del args['per_page']
except KeyError:
pass
# Paginate the query.
resources = query.paginate(page, per_page, False)
# Generate the response dictionary.
data = {
'items': [item.to_dict() for item in resources.items],
'_meta': {
'page': page,
'per_page': per_page,
'total_pages': resources.pages,
'total_items': resources.total
},
'_links': {
'self': url_for(endpoint, page=page, per_page=per_page, **args),
'next': url_for(endpoint, page=page + 1, per_page=per_page, **args) if resources.has_next else None,
'prev': url_for(endpoint, page=page - 1, per_page=per_page, **args) if resources.has_prev else None
}
}
return data
Я понимаю, что я могу получить отфильтрованный список предупреждений по их имени, связанного с событием, что-то в этом духес параметрами и contains_eager:
alerts = db.session.query(Alert).join(Alert.event).options(contains_eager(Alert.event)).filter(Event.name.like('%{}%'.format(request.args.get('event')))).all()
Но я не получил что-то подобное, чтобы работать при добавлении в набор фильтров.