Как разбивать страницы на Flask-SQLAlchemy для связанных с db.session запросов?

Скажем, мы имеем следующие отношения:

  • у человека может быть много адресов электронной почты
  • поставщик услуг электронной почты может (очевидно) обслуживать несколько адресов электронной почты

Таким образом, это много-много отношений. У меня три таблицы: электронные письма, поставщики и пользователи. У электронных писем есть два внешних идентификатора для провайдера и пользователя.

Теперь, учитывая конкретного человека, я хочу распечатать всех поставщиков электронной почты и адрес электронной почты, который он размещает для этого человека, если он существует. (Если у человека нет электронной почты в Gmail, я все равно хочу, чтобы Gmail был в результате. В противном случае мне нужно только левое внутреннее соединение, чтобы решить эту проблему.)

Я понял, как это сделать с помощью следующих подзапросов (после учебника по sqlalchemy):

email_subq = db.session.query(Emails).\ filter(Emails.user_id==current_user.id).\ subquery() provider_and_email = db.session.query(Provider, email_subq).\ outerjoin(email_subq, Provider.emails).\ all() 

Это работает нормально (он возвращает 4-кортеж (Provider, user_id, provider_id, email_address) , всю информацию, которую я хочу), но позже я узнал, что это не использует класс Flask BaseQuery , так что pagination предоставленное Flask- SQLAlchemy не работает. По-видимому, db.session.query() не является экземпляром db.session.query() -SQLAlchemy Query.

Я пытался сделать Emails.query.outerjoin[...] но он возвращает только столбцы в таблице электронной почты, хотя я хочу как информацию о провайдере, так и электронные письма.

Мой вопрос : как я могу сделать то же самое с Flask-SQLAlchemy, чтобы мне не пришлось повторно выполнять разбивку на страницы, которая уже существует?


Я думаю, самый простой вариант на этом этапе – реализовать мою собственную функцию paginate, но я хотел бы знать, есть ли другой правильный способ сделать это.

6 Solutions collect form web for “Как разбивать страницы на Flask-SQLAlchemy для связанных с db.session запросов?”

Я не уверен, что в конечном итоге это будет долгосрочное решение, и оно напрямую не касается моей озабоченности по поводу того, что вы не используете BaseQuery из Flask-SQLAlchemy, но самый простой способ сделать то, что я хочу, – это переопределить функция paginate.

И, на самом деле, довольно просто использовать оригинальную процедуру Flask-SQLAlchemy для этого:

 def paginate(query, page, per_page=20, error_out=True): if error_out and page < 1: abort(404) items = query.limit(per_page).offset((page - 1) * per_page).all() if not items and page != 1 and error_out: abort(404) # No need to count if we're on the first page and there are fewer # items than we expected. if page == 1 and len(items) < per_page: total = len(items) else: total = query.order_by(None).count() return Pagination(query, page, per_page, total, items) 

Изменен из функции paginate найденной вокруг строки 376: https://github.com/mitsuhiko/flask-sqlalchemy/blob/master/flask_sqlalchemy.py

Ваш вопрос заключается в том, как использовать разбиение на Flask-SQLAlchemy с регулярными запросами SQLAlchemy.

Поскольку объект BaseQuery Flask-SQLAlchemy не имеет собственного состояния и получен из запроса SQLAlchemy, и на самом деле это просто контейнер для методов, вы можете использовать этот хак:

 from flask.ext.sqlalchemy import BaseQuery def paginate(sa_query, page, per_page=20, error_out=True): sa_query.__class__ = BaseQuery # We can now use BaseQuery methods like .paginate on our SA query return sa_query.paginate(page, per_page, error_out) 

Использовать:

 @route(...) def provider_and_email_view(page): provider_and_email = db.session.query(...) # any SQLAlchemy query paginated_results = paginate(provider_and_email, page) return render_template('...', paginated_results=paginated_results) 

*Редактировать:

Пожалуйста, будьте осторожны. Это действительно просто способ избежать копирования / вставки функции paginate , как видно из другого ответа. Обратите внимание: BaseQuery не имеет метода __init__ . См. Как опасно устанавливать self.__class__ для чего-то еще? ,

* Edit2:

Если у BaseQuery был __init__ , вы могли бы построить его с использованием объекта запроса SA, а не взломать .__class__ .

Эй, я нашел быстрое решение для этого здесь:

 provider_and_email = Provider.query.with_entities(email_subq).\ outerjoin(email_subq, Provider.emails).paginate(page, POST_PER_PAGE_LONG, False) 

В настоящее время я использую этот подход:

 query = BaseQuery([Provider, email_subq], db.session()) 

для создания моего собственного BaseQuery . db – экземпляр SqlAlchemy .

Обновление: как @afilbert предлагает вам также сделать это:

 query = BaseQuery(provider_and_email.subquery(), db.session()) 

Я могу ошибаться, но я думаю, что ваша проблема может быть .all (). Используя это, вы получаете список, а не объект запроса.

Попытайтесь оставить его и передайте свой запрос методу разбивки на страницы так, как я (я просто отказался от всех данных в подзапросах):

 email_query = db.session.query(Emails).filter(**filters) email_query.paginate(page, per_page) 

Как запустить приложение с помощью SQLAlchemy?

Вероятно, ваше текущее соединение SQLAlchemy не имеет ничего общего с flask.ext.sqalchemy, и вы используете оригинальную sqlalchemy

Проверьте этот учебник и проверьте свой импорт, что они действительно поступают из flask.ext.sqlalchemy

http://pythonhosted.org/Flask-SQLAlchemy/quickstart.html#a-minimal-application

  • Отслеживание изменений модели в SQLAlchemy
  • Установите SQLAlchemy для использования PostgreSQL SERIAL для создания идентичности
  • Написание строки подключения, когда пароль содержит специальные символы
  • Может ли кто-нибудь сказать, что случилось с моими отношениями?
  • Неверная транзакция, сохраняющаяся во всех запросах
  • Почему Flask-migrate не может обновляться при столбце падения
  • Один объект два внешних ключа к одной таблице
  • Можно ли выполнять код при импорте модуля?
  • Python SQLAlchemy и Postgres - как запросить элемент JSON
  • Почему я получаю «NameError» с этим импортом?
  • SQLAlchemy delete не каскадирует
  • Python - лучший язык программирования в мире.