在Flask视图函数中使用多个路由是坏实践吗?
基本上,我有多个 render_template
的返回值,这些返回值是根据条件语句来决定的,它们返回不同的变量,而我的 jinja2 模板会根据这些变量做出反应。我觉得我可以把这些路由分成自己的函数(同样,我也可以把我的模板拆分成多个模板,比如用一个 edit.html 模板,而不是在我的模板里用 {% if editform %}
),但我更喜欢为每个页面使用一个单独的视图函数和模板。
在我花更多时间创建其他视图函数之前,我想确保我现在做的不会在以后给我带来麻烦。
下面是代码,谢谢!
@app.route('/admin/users/', defaults={'id': None}, methods = ['GET'])
@app.route('/admin/users/<id>', methods = ['GET'])
@app.route('/admin/users/edit/<id>', methods = ['GET', 'POST'])
@login_required
def users(id):
if not current_user.role == ROLE_ADMIN:
flash('You do not have access to view this page.')
return redirect(url_for('index'))
if id:
user = User.query.filter_by(id = id).first()
if 'edit' in request.path:
editform = UserForm()
if editform.validate_on_submit():
user.username = editform.username.data
user.email = editform.email.data
user.role = editform.role.data
db.session.add(user)
db.session.commit()
return redirect('/admin/users/' + str(user.id))
editform.username.data = user.username
editform.email.data = user.email
editform.role.data = user.role
return render_template("users.html",
title = "Edit User",
user = user,
editform = editform)
return render_template("users.html",
title = "User",
user = user)
users = User.query.all()
return render_template("users.html",
title = 'Users',
users = users)
2 个回答
没有绝对的规则,但我建议把代码分成多个函数,这样更符合关注点分离的原则。
我甚至可以更进一步,使用MethodView,这样每个路由都有一个类,里面可以重写get、post等方法。
当你的函数很小的时候,看起来还不错,但当它变得复杂时,分模块会更有帮助!
这个问题的答案可能有点个人偏好,但我个人会避免这样做。我的主要原因就是为了保持简单——在这个函数里有三个嵌套的if语句,它们基本上在做和Flask路由逻辑一样的事情,如果你把视图分开的话。
虽然现在这不是个大问题,但如果你在任何路径中添加更多逻辑,可能会导致这个函数变得意外复杂。这可能会引发一些微妙的错误,或者让人一眼看上去就搞不清楚到底发生了什么。
但是如果你把这些东西分开,那么一眼就能看出每个路由在做什么。这样甚至不需要更多的代码,因为你可以省去所有的if语句:
@app.route('/admin/users/', methods = ['GET'])
def get_all_users():
users = User.query.all()
return render_template("users.html",
title = 'Users',
users = users)
@app.route('/admin/users/<id>', methods = ['GET'])
def get_single_user(id):
user = User.query.filter_by(id = id).first()
return render_template("users.html",
title = "User",
user = user)
@app.route('/admin/users/edit/<id>', methods = ['GET', 'POST'])
def edit_user(id):
editform = UserForm()
if editform.validate_on_submit():
user.username = editform.username.data
user.email = editform.email.data
user.role = editform.role.data
db.session.add(user)
db.session.commit()
return redirect('/admin/users/' + str(user.id))
editform.username.data = user.username
editform.email.data = user.email
editform.role.data = user.role
return render_template("users.html",
title = "Edit User",
user = user,
editform = editform)
补充说明:我并不是说每个Flask路由只能有一个URL。在这种情况下,我认为让一个函数做三件相当不同的事情是个坏主意。我确实有其他情况下会用到每个视图多个路由的情况。例如,在我自己的代码中,我经常会有这样的视图:
@migrations_tasks.route('/external_applications', methods=['GET'])
@migrations_tasks.route('/external_applications/<cursor>', methods=['POST'])
def migrate_external_applications(cursor=None, subdomain=None):
... do stuff
其中替代路由接受一个数据库查询的游标,用于分页。代码的流程基本上是一样的,只是首页和后续页面有不同的URL。