今天遇到一個問題,用flask-sqlalchemy的paginate做分頁的時候,發現聯表查詢時分頁出來結果數據少了很多,直接all()出來就沒問題,把sql單獨執行發現是聯表查時有重複數據,group一下就好了,但是all()結果沒有重複的,all()還給濾重了?而且paginate還是在濾重前做的limit,所以去重後結果就少了,而且還影響了total的值,趁這個機會看一下flask-sqlalchemy的源碼吧
class BaseQuery(orm.Query):
def paginate(self, page=None, per_page=None, error_out=True, max_per_page=None, count=True):
"""
當“error_out”為"True"時,符合下面判斷時將引起404響應,我一般都關了這個
error_out,把接口返回什麼的控制權拿回來。
"""
//如果"page"或"per-page"是"None",則將從請求查詢
//flask-sqlalchemy和flask app綁定的還真是挺深,連request都用上了
if request:
if page is None:
try:
//這麼寫更好page = request.args.get('page', 1, type=int)
page = int(request.args.get('page', 1))
except (TypeError, ValueError):
if error_out:
abort(404)
page = 1
if per_page is None:
try:
per_page = int(request.args.get('per_page', 20))
except (TypeError, ValueError):
if error_out:
abort(404)
per_page = 20
else: // 如果沒有請求分別默認為1和20
if page is None:
page = 1
if per_page is None:
per_page = 20
//如果指定了“max_per_page”,則“per_page”將受這個值鉗制。
if max_per_page is not None:
per_page = min(per_page, max_per_page)
if page < 1:
......
page = 1
if per_page < 0:
......
per_page = 20
//原來paginate就是用的limit和offset,我猜如果有重複數據,先limit後all,all的時候再去個重,數據就少了,分頁也沒了
items = self.limit(per_page).offset((page - 1) * per_page).all()
......
//如果"count"是"False",total就不能用了,不用的時候可以關掉,省個查詢
if not count:
total = None
else:
//為什麼order_by(None)?
total = self.order_by(None).count()
return Pagination(self, page, per_page, total, items)
class Pagination(object):
def __init__(self, query, page, per_page, total, items):
#: the unlimited query object that was used to create this
#: pagination object.
self.query = query
#: the current page number (1 indexed)
self.page = page
#: the number of items to be displayed on a page.
self.per_page = per_page
#: the total number of items matching the query
self.total = total
#: the items for the current page
self.items = items
......
flask-sqlalchemy代碼沒有去重,再看看sqlalchemy的代碼
class Query(Generative):
......
def all(self):
"""
不翻譯了,留著原話,這裡給去重了
Return the results represented by this :class:`_query.Query`
as a list.
This results in an execution of the underlying SQL statement.
.. warning:: The :class:`_query.Query` object,
when asked to return either
a sequence or iterator that consists of full ORM-mapped entities,
will **deduplicate entries based on primary key**. See the FAQ for
more details.
.. seealso::
:ref:`faq_query_deduplicating`
"""
return self._iter().all()
......
到此,可知sqlalchemy的all()操作是去重了的
參考
https://github.com/pallets/flask-sqlalchemy
https://github.com/sqlalchemy/sqlalchemy