Flask 系列之 Pagination
阿新 • • 發佈:2019-04-03
boot 通過 設置 分享圖片 aps port 技術分享 secondary ted
說明
- 操作系統:Windows 10
- Python 版本:3.7x
- 虛擬環境管理器:virtualenv
- 代碼編輯器:VS Code
實驗目標
實現當前登錄用戶的事務瀏覽、添加、刪除 操作
實現
首先,在我們的 todolist\forms.py
中添加事務添加對應的表單類 ThingForm,示例代碼如下所示:
from flask_wtf import FlaskForm from wtforms import StringField, SubmitField, TextAreaField, PasswordField from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError from models import User class RegisterForm(FlaskForm): username = StringField('用戶名:', validators=[ DataRequired(), Length(min=6, max=20)]) email = StringField('郵箱:', validators=[DataRequired(), Email()]) pwd = PasswordField('密碼:', validators=[ DataRequired(), Length(min=8, max=120)]) confirm = PasswordField('確認密碼:', validators=[ DataRequired(), EqualTo('pwd')]) submit = SubmitField('提交') def validate_username(self, username): user = User.query.filter_by(name=username.data).first() if user: raise ValidationError("用戶昵稱已存在。") def validate_email(self, email): user = User.query.filter_by(email=email.data).first() if user: raise ValidationError('郵箱已存在.') class LoginForm(FlaskForm): username = StringField('用戶名:', validators=[ DataRequired(), Length(min=6, max=20)]) password = PasswordField('密碼:', validators=[DataRequired()]) submit = SubmitField('登陸') def validate_username(self, username): user = User.query.filter_by(name=username.data) if not user: raise ValidationError('用戶名不存在。') class ThingForm(FlaskForm): title = StringField('標題:', validators=[ DataRequired(), Length(min=6, max=20)]) text = TextAreaField('內容:', validators=[DataRequired()]) submit = SubmitField('提交')
接著修改 todolist\app\views.py
,添加當前用戶事務的添加、刪除,示例代碼如下所示:
from flask import render_template, redirect, url_for, flash, request from flask_login import login_user, login_required, current_user, logout_user from app import app, db from forms import ThingForm, RegisterForm, LoginForm from models import User, Thing @app.context_processor def inject_user(): user = User.query.first() return dict(user=user) @app.route('/', methods=['GET', 'POST']) @app.route('/index', methods=['GET', 'POST']) def index(): form = ThingForm() if not current_user.is_authenticated: return redirect(url_for('login')) if request.method == 'POST' and form.validate_on_submit(): user_id = current_user.id title = form.title.data text = form.text.data thing = Thing(user_id=user_id, title=title, text=text) db.session.add(thing) db.session.commit() flash('添加成功') page = request.args.get('page', 1, type=int) things = current_user.things.order_by( Thing.add_date.desc()).paginate(page, 2, False) print(things) return render_template('index.html', title="首頁", form=form, things=things) @app.route('/login', methods=['POST', 'GET']) def login(): form = LoginForm() if form.validate_on_submit(): name = form.username.data pwd = form.password.data user = User.query.filter_by(name=name).first() if user and user.check_password_hash(pwd): login_user(user) flash('登陸成功。', category='info') return redirect(url_for('index')) else: flash("密碼或賬戶錯誤。", category='error') return render_template('login.html', title='登錄', form=form) @app.route('/logout') @login_required def logout(): logout_user() flash('再見!') return redirect(url_for('login')) @app.route('/register', methods=['POST', 'GET']) def register(): form = RegisterForm() if form.validate_on_submit(): username = form.username.data email = form.email.data pwd = form.pwd.data user = User(name=username, email=email) user.generate_password_hash(pwd) db.session.add(user) db.session.commit() flash('註冊成功', category='info') return redirect(url_for('login')) return render_template('register.html', title='註冊', form=form) @app.route('/delete/<int:id>') @login_required def delete(id): thing = Thing.query.get(id) if thing: db.session.delete(thing) db.session.commit() return redirect(url_for('index'))
最後,完善 todolist\app\templates\index.html
,添加數據展示相關代碼,示例代碼如下所示:
{% extends 'base.html' %} {% block content %} {% if current_user.is_authenticated and user %} <h1 class="m-4">{{ current_user.name }},歡迎回來</h1> {% endif %} <div class="container-fluid"> <p> <a class="btn btn-primary" data-toggle="collapse" href="#collapseExample" role="button" aria-expanded="false" aria-controls="collapseExample"> 添加新事務 </a> </p> <div class="collapse" id="collapseExample"> <div class="card card-body mb-4"> {% from 'bootstrap/form.html' import render_form %} {{ render_form(form) }} </div> </div> <ul class="list-group"> {% for thing in things.items %} <li class="list-group-item"> <h4 style="display:block;float:left;padding-top:2px"> {{ thing.title }} </h4> <div style="display:block;float: right;"> <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModalCenter{{thing.id}}">查看</button> <a class="btn btn-danger" href='/delete/{{ thing.id }}'>刪除</a> </div> </li> <div class="modal fade" id="exampleModalCenter{{thing.id}}" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true"> <div class="modal-dialog modal-dialog-centered" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="exampleModalLongTitle">{{ thing.title }}</h5> </div> <div class="modal-body"> {{ thing.text }} </div> <div class="modal-footer"> <small>{{ thing.add_date }}</small> <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> </div> </div> </div> </div> {% endfor %} </ul> <nav aria-label="Page navigation example" class="m-4"> <ul class="pagination justify-content-center"> <li class="page-item {% if not things.has_prev %}disabled{% endif %}"> <a class="page-link" href="{{ url_for('index',page=things.prev_num) }}">上一頁</a> </li> {% for page in things.iter_pages(1,1,3,2) %} {% if page %} <li class="page-item {%if page==things.page%}active{%endif%}"> <a class="page-link" href="{{ url_for('index',page=page) }}">{{page}}</a> </li> {% else %} <li class="page-item disabled"> <a class="page-link" href="#">…</a> </li> {% endif %} {% endfor %} <li class="page-item {% if not things.has_next %}disabled{% endif %}"> <a class="page-link" href="{{ url_for('index',page=things.next_num) }}">下一頁</a> </li> </ul> </nav> </div> {% endblock %}
此時,當我們運行起我們的網站後進入註冊頁面 http://127.0.0.1:5000 就可以進行當前登錄用戶的事務錄入、查看、刪除、和事務分頁的效果了。
補充
一個 Pagination 對象的常用屬性有:
- items 當前頁面中的所有記錄(比如當前頁上有5條記錄,items就是以列表形式組織這5個記錄)
- query 當前頁的query對象(通過query對象調用paginate方法獲得的Pagination對象)
- page 當前頁碼(比如當前頁是第5頁,返回5)
- prev_num 上一頁頁碼
- next_num 下一頁頁碼
- has_next 是否有下一頁 True/False
- has_prev 是否有上一頁 True/False
- pages 查詢得到的總頁數 per_page 每頁顯示的記錄條數
- total 總的記錄條數
常用方法有:
- prev() 上一頁的分頁對象Pagination
- next() 下一頁的分頁對象Pagination
- iter_pages(left_edge=2,left_current=2,right_current=5,right_edge=2)
- iter_pages 用來獲得針對當前頁的應顯示的分頁頁碼列表。
- 假設當前共有100頁,當前頁為50頁,按照默認的參數設置調用iter_pages獲得的列表為:[1,2,None,48,49,50,51,52,53,54,55,None,99,100]
Flask 系列之 Pagination