默认情况下如何转到分页 Flask-Admin 视图的最后一页.. 不降序排序
How to go to the last page of paginated Flask-Admin view by default.. without sorting descending
在 Python 的数据库 table viewing/administrating 的 Flask-Admin 中,我需要视图自动打开到分页数据的最后一页。
重要提示:我不能简单地对记录进行降序排序,所以最后一条记录排在最前面。
下面是我的简单示例。我希望它从最后一页开始,如图所示。
下面是一些重现我的模型的示例代码:
import os
import os.path as op
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import flask_admin as admin
from flask_admin.contrib.sqla import ModelView
# Create application
app = Flask(__name__)
# Create dummy secrey key so we can use sessions
app.config['SECRET_KEY'] = '123456790'
# Create in-memory database
app.config['DATABASE_FILE'] = 'sample_db2.sqlite'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + app.config['DATABASE_FILE']
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
# Models
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Unicode(64))
email = db.Column(db.Unicode(64))
def __unicode__(self):
return self.name
class UserAdmin(ModelView):
column_searchable_list = ('name', 'email')
column_editable_list = ('name', 'email')
column_display_pk = True
can_set_page_size = True
# the number of entries to display in the list view
page_size = 5
# Flask views
@app.route('/')
def index():
return '<a href="/admin/">Click me to get to Admin!</a>'
admin = admin.Admin(app, 'Example', template_mode='bootstrap3')
# Add views
admin.add_view(UserAdmin(User, db.session))
def build_sample_db():
"""
Populate a small db with some example entries.
"""
db.drop_all()
db.create_all()
first_names = [
'Harry', 'Amelia', 'Oliver', 'Jack', 'Isabella', 'Charlie','Sophie', 'Mia',
'Jacob', 'Thomas', 'Emily', 'Lily', 'Ava', 'Isla', 'Alfie', 'Olivia', 'Jessica',
'Riley', 'William', 'James', 'Geoffrey', 'Lisa', 'Benjamin', 'Stacey', 'Lucy'
]
last_names = [
'Brown', 'Smith', 'Patel', 'Jones', 'Williams', 'Johnson', 'Taylor', 'Thomas',
'Roberts', 'Khan', 'Lewis', 'Jackson', 'Clarke', 'James', 'Phillips', 'Wilson',
'Ali', 'Mason', 'Mitchell', 'Rose', 'Davis', 'Davies', 'Rodriguez', 'Cox', 'Alexander'
]
for i in range(len(first_names)):
user = User()
user.name = first_names[i] + " " + last_names[i]
user.email = first_names[i].lower() + "@example.com"
db.session.add(user)
db.session.commit()
return
if __name__ == '__main__':
# Build a sample db on the fly, if one does not exist yet.
app_dir = op.realpath(os.path.dirname(__file__))
database_path = op.join(app_dir, app.config['DATABASE_FILE'])
if not os.path.exists(database_path):
build_sample_db()
# Start app
app.run(debug=True, host='0.0.0.0')
下面的想法呢:
# Flask views
@app.route('/')
def index():
# from sqlalchemy import func
# n=(db.session.query(func.count(User.id)).all())[0][0]
# or
n=len(User.query.all())
last_page=int((n-1)/UserAdmin.page_size)
return f'<a href="/admin/user/?page={last_page}">Click me to get to Admin!</a>'
我找到了一个理想的解决方案,覆盖了 flask_admin.contrib.sqla.ModelView
class.
中的 index_view()
模板渲染视图方法
class UserAdmin(ModelView):
column_searchable_list = ('name', 'email')
column_editable_list = ('name', 'email')
column_display_pk = True
can_set_page_size = True
# the number of entries to display in the list view
page_size = 5
# Now to override the index_view method
@expose('/')
def index_view(self):
"""List view overridden to DEFAULT to the last page,
if no other request args have been submitted"""
if self.can_delete:
delete_form = self.delete_form()
else:
delete_form = None
# Grab parameters from URL
view_args = self._get_list_extra_args()
# Map column index to column name
sort_column = self._get_column_by_idx(view_args.sort)
if sort_column is not None:
sort_column = sort_column[0]
# Get page size
page_size = view_args.page_size or self.page_size
#####################################################################
# Custom functionality to start on the last page instead of the first
if len(request.args) == 0:
# Standard request for the first page (no additional args)
count_query = self.get_count_query() if not self.simple_list_pager else None
# Calculate number of rows if necessary
count = count_query.scalar() if count_query else None
# Calculate number of pages
if count is not None and page_size:
num_pages = int(ceil(count / float(page_size)))
# Change the page to the last page (minus 1 for zero-based counting)
setattr(view_args, 'page', num_pages - 1)
# End of custom code. The rest below is from the Flask-Admin package
############################################################################
# Get database data for the view_args.page requested
count, data = self.get_list(view_args.page, sort_column, view_args.sort_desc,
view_args.search, view_args.filters, page_size=page_size)
list_forms = {}
if self.column_editable_list:
for row in data:
list_forms[self.get_pk_value(row)] = self.list_form(obj=row)
# Calculate number of pages
if count is not None and page_size:
num_pages = int(ceil(count / float(page_size)))
elif not page_size:
num_pages = 0 # hide pager for unlimited page_size
else:
num_pages = None # use simple pager
# Various URL generation helpers
def pager_url(p):
# Do not add page number if it is first page
if p == 0:
p = None
return self._get_list_url(view_args.clone(page=p))
def sort_url(column, invert=False, desc=None):
if not desc and invert and not view_args.sort_desc:
desc = 1
return self._get_list_url(view_args.clone(sort=column, sort_desc=desc))
def page_size_url(s):
if not s:
s = self.page_size
return self._get_list_url(view_args.clone(page_size=s))
# Actions
actions, actions_confirmation = self.get_actions_list()
if actions:
action_form = self.action_form()
else:
action_form = None
clear_search_url = self._get_list_url(view_args.clone(page=0,
sort=view_args.sort,
sort_desc=view_args.sort_desc,
search=None,
filters=None))
return self.render(
self.list_template,
data=data,
list_forms=list_forms,
delete_form=delete_form,
action_form=action_form,
# List
list_columns=self._list_columns,
sortable_columns=self._sortable_columns,
editable_columns=self.column_editable_list,
list_row_actions=self.get_list_row_actions(),
# Pagination
count=count,
pager_url=pager_url,
num_pages=num_pages,
can_set_page_size=self.can_set_page_size,
page_size_url=page_size_url,
page=view_args.page,
page_size=page_size,
default_page_size=self.page_size,
# Sorting
sort_column=view_args.sort,
sort_desc=view_args.sort_desc,
sort_url=sort_url,
# Search
search_supported=self._search_supported,
clear_search_url=clear_search_url,
search=view_args.search,
search_placeholder=self.search_placeholder(),
# Filters
filters=self._filters,
filter_groups=self._get_filter_groups(),
active_filters=view_args.filters,
filter_args=self._get_filters(view_args.filters),
# Actions
actions=actions,
actions_confirmation=actions_confirmation,
# Misc
enumerate=enumerate,
get_pk_value=self.get_pk_value,
get_value=self.get_list_value,
return_url=self._get_list_url(view_args),
# Extras
extra_args=view_args.extra_args,
)
在 Python 的数据库 table viewing/administrating 的 Flask-Admin 中,我需要视图自动打开到分页数据的最后一页。
重要提示:我不能简单地对记录进行降序排序,所以最后一条记录排在最前面。
下面是我的简单示例。我希望它从最后一页开始,如图所示。
下面是一些重现我的模型的示例代码:
import os
import os.path as op
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import flask_admin as admin
from flask_admin.contrib.sqla import ModelView
# Create application
app = Flask(__name__)
# Create dummy secrey key so we can use sessions
app.config['SECRET_KEY'] = '123456790'
# Create in-memory database
app.config['DATABASE_FILE'] = 'sample_db2.sqlite'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + app.config['DATABASE_FILE']
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
# Models
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Unicode(64))
email = db.Column(db.Unicode(64))
def __unicode__(self):
return self.name
class UserAdmin(ModelView):
column_searchable_list = ('name', 'email')
column_editable_list = ('name', 'email')
column_display_pk = True
can_set_page_size = True
# the number of entries to display in the list view
page_size = 5
# Flask views
@app.route('/')
def index():
return '<a href="/admin/">Click me to get to Admin!</a>'
admin = admin.Admin(app, 'Example', template_mode='bootstrap3')
# Add views
admin.add_view(UserAdmin(User, db.session))
def build_sample_db():
"""
Populate a small db with some example entries.
"""
db.drop_all()
db.create_all()
first_names = [
'Harry', 'Amelia', 'Oliver', 'Jack', 'Isabella', 'Charlie','Sophie', 'Mia',
'Jacob', 'Thomas', 'Emily', 'Lily', 'Ava', 'Isla', 'Alfie', 'Olivia', 'Jessica',
'Riley', 'William', 'James', 'Geoffrey', 'Lisa', 'Benjamin', 'Stacey', 'Lucy'
]
last_names = [
'Brown', 'Smith', 'Patel', 'Jones', 'Williams', 'Johnson', 'Taylor', 'Thomas',
'Roberts', 'Khan', 'Lewis', 'Jackson', 'Clarke', 'James', 'Phillips', 'Wilson',
'Ali', 'Mason', 'Mitchell', 'Rose', 'Davis', 'Davies', 'Rodriguez', 'Cox', 'Alexander'
]
for i in range(len(first_names)):
user = User()
user.name = first_names[i] + " " + last_names[i]
user.email = first_names[i].lower() + "@example.com"
db.session.add(user)
db.session.commit()
return
if __name__ == '__main__':
# Build a sample db on the fly, if one does not exist yet.
app_dir = op.realpath(os.path.dirname(__file__))
database_path = op.join(app_dir, app.config['DATABASE_FILE'])
if not os.path.exists(database_path):
build_sample_db()
# Start app
app.run(debug=True, host='0.0.0.0')
下面的想法呢:
# Flask views
@app.route('/')
def index():
# from sqlalchemy import func
# n=(db.session.query(func.count(User.id)).all())[0][0]
# or
n=len(User.query.all())
last_page=int((n-1)/UserAdmin.page_size)
return f'<a href="/admin/user/?page={last_page}">Click me to get to Admin!</a>'
我找到了一个理想的解决方案,覆盖了 flask_admin.contrib.sqla.ModelView
class.
index_view()
模板渲染视图方法
class UserAdmin(ModelView):
column_searchable_list = ('name', 'email')
column_editable_list = ('name', 'email')
column_display_pk = True
can_set_page_size = True
# the number of entries to display in the list view
page_size = 5
# Now to override the index_view method
@expose('/')
def index_view(self):
"""List view overridden to DEFAULT to the last page,
if no other request args have been submitted"""
if self.can_delete:
delete_form = self.delete_form()
else:
delete_form = None
# Grab parameters from URL
view_args = self._get_list_extra_args()
# Map column index to column name
sort_column = self._get_column_by_idx(view_args.sort)
if sort_column is not None:
sort_column = sort_column[0]
# Get page size
page_size = view_args.page_size or self.page_size
#####################################################################
# Custom functionality to start on the last page instead of the first
if len(request.args) == 0:
# Standard request for the first page (no additional args)
count_query = self.get_count_query() if not self.simple_list_pager else None
# Calculate number of rows if necessary
count = count_query.scalar() if count_query else None
# Calculate number of pages
if count is not None and page_size:
num_pages = int(ceil(count / float(page_size)))
# Change the page to the last page (minus 1 for zero-based counting)
setattr(view_args, 'page', num_pages - 1)
# End of custom code. The rest below is from the Flask-Admin package
############################################################################
# Get database data for the view_args.page requested
count, data = self.get_list(view_args.page, sort_column, view_args.sort_desc,
view_args.search, view_args.filters, page_size=page_size)
list_forms = {}
if self.column_editable_list:
for row in data:
list_forms[self.get_pk_value(row)] = self.list_form(obj=row)
# Calculate number of pages
if count is not None and page_size:
num_pages = int(ceil(count / float(page_size)))
elif not page_size:
num_pages = 0 # hide pager for unlimited page_size
else:
num_pages = None # use simple pager
# Various URL generation helpers
def pager_url(p):
# Do not add page number if it is first page
if p == 0:
p = None
return self._get_list_url(view_args.clone(page=p))
def sort_url(column, invert=False, desc=None):
if not desc and invert and not view_args.sort_desc:
desc = 1
return self._get_list_url(view_args.clone(sort=column, sort_desc=desc))
def page_size_url(s):
if not s:
s = self.page_size
return self._get_list_url(view_args.clone(page_size=s))
# Actions
actions, actions_confirmation = self.get_actions_list()
if actions:
action_form = self.action_form()
else:
action_form = None
clear_search_url = self._get_list_url(view_args.clone(page=0,
sort=view_args.sort,
sort_desc=view_args.sort_desc,
search=None,
filters=None))
return self.render(
self.list_template,
data=data,
list_forms=list_forms,
delete_form=delete_form,
action_form=action_form,
# List
list_columns=self._list_columns,
sortable_columns=self._sortable_columns,
editable_columns=self.column_editable_list,
list_row_actions=self.get_list_row_actions(),
# Pagination
count=count,
pager_url=pager_url,
num_pages=num_pages,
can_set_page_size=self.can_set_page_size,
page_size_url=page_size_url,
page=view_args.page,
page_size=page_size,
default_page_size=self.page_size,
# Sorting
sort_column=view_args.sort,
sort_desc=view_args.sort_desc,
sort_url=sort_url,
# Search
search_supported=self._search_supported,
clear_search_url=clear_search_url,
search=view_args.search,
search_placeholder=self.search_placeholder(),
# Filters
filters=self._filters,
filter_groups=self._get_filter_groups(),
active_filters=view_args.filters,
filter_args=self._get_filters(view_args.filters),
# Actions
actions=actions,
actions_confirmation=actions_confirmation,
# Misc
enumerate=enumerate,
get_pk_value=self.get_pk_value,
get_value=self.get_list_value,
return_url=self._get_list_url(view_args),
# Extras
extra_args=view_args.extra_args,
)