简体   繁体   中英

Can Flask-SQLAlchemy's Pagination class be used with a Python list?

I have a list of posts that I queried from SQLAlchemy. However, it's just a Python list now, not a query, so I can't use Flask-SQLAlchemy's query.paginate() method. Is it possible to use Flask-SQLAlchemy's Paginate class to paginate the list instead of a query?

from  flask_sqlalchemy import Pagination
from flask_app.model import Post
 
recommended_posts_title = ['the sea', 'loving better', 'someones mother']
posts = [Post.query.filter_by(title=title).first() for title in recommended_posts_title]

You can use Flask-SQLAlchemy's Pagination class, but need to manually get the page number and slice the data.

The docs show the parameters that Pagination takes: Pagination(query, page, per_page, total, items) .

Since we don't have a query in this case, we'll pass None for query . We'll get the page from the query string ( http://localhost/home/posts?page=1 ), and use 20 for per_page . We can get total with len() , then slice our data to get 20 items from the page offset.

from flask_sqlalchemy import Pagination
from flask import Flask,request,render_template
from flask_app.model import Post

app = Flask(__name__)

@app.route("/recommended-posts", methods = ['GET'])
def recommended_post():
    recommended_titles = ['the sea', 'loving better', 'someones mother']
    posts = [Post.query.filter_by(title=title).first() for title in titles]
    page = request.args.get('page', 1, type=int)
    # get the start and end index based on page number
    start = (page - 1) * 20
    end = start + 20
    # page 1 is [0:20], page 2 is [20:41]
    items = posts[start:end]
    pagination = Pagination(None, page, 20, len(items), items)
    return render_template('blog/posts.html', pagination=pagination)

Use the pagination object as you normally would.

{% for item in pagination.items %}
    render post
{% endfor %}

{% if pagination.has_prev %}
    <a href="{{ url_for("recommended_posts", page=pagination.prev_num) }}">Previous</a>
{% endif %}

{% if pagination.has_next %}
    <a href="{{ url_for("recommended_posts", page=pagination.next_num) }}">Next</a>
{% endif %}

For what it is still worth after more than a year:

I recently encountered the same issue since my results could not be obtained from a single query and had to be build it iteratively resulting in a "list of results".

Based on this answer , I came up with the following function to convert a list of results to a Pagination object:

from flask_sqlalchemy import Pagination

def paginate(data, page, per_page):
    # Based on page and per_page info, calculate start and end index of items to keep
    start_index = (page - 1) * per_page
    end_index = start_index + per_page

    # Get the paginated list of items
    items = data[start_index:end_index]

    # Create Pagination object
    return Pagination(None, page, per_page, len(data), items)

This is for future users and a really clean and simple solution, I hope it works for you. I was running into the same problem not being able to use paginate in Flask-SQLAlchemy because its not compatible with lists ...

I tried using other library's but its an understatement to say they were cumbersome and didn't have enough features built in.

def project(page, proj_type='mini'):
    per_page = 3
    return ProjectPost.query.filter(ProjectPost.type == proj_type).paginate(page=page, per_page=per_page, error_out=False)

type is a column in my dB, I have three types and each one is for a different page with pagination.

So Filter() returns the query object itself, allowing us to chain more query options aka paginate...

On the other hand filter_by() returns the query objects but also calls all() method on the query object automatically so it returns a list of matched results.

TLDR: use filter() for chaining operations and keep them as objects.

You need to read https://flask-sqlalchemy.palletsprojects.com/en/2.x/api/#flask_sqlalchemy.Pagination So what you need to do is build query object from sqlalchemy. Then you pass that query object to Pagnination class to get an object and then you simply pass that to your template.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM