Ответ 1
маршруты отладки:
Обновление: для решения основного вопроса "что не так с моими маршрутами", самый простой способ отладки - использовать app.url_map
; например:
>>> app.url_map
Map([<Rule '/user/<id>/<username>/' (HEAD, OPTIONS, GET) -> profile>,
<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/user/<id>/' (HEAD, OPTIONS, GET) -> profile>])
В этом случае это подтверждает правильность установки конечной точки.
Вот пример, демонстрирующий как простые flask
, так и flask-classy
:
from app import app, models
from flask import g, redirect, url_for, render_template, request
from flask.ext.classy import FlaskView, route
@app.route('/user/<int:id>', strict_slashes=False)
@app.route('/user/<int:id>/<username>', strict_slashes=False)
def profile(id, username=None):
user = models.User.query.get_or_404(id)
if user.clean_username != username:
return redirect(url_for('profile', id=id, username=user.clean_username))
return render_template('profile.html', user=user)
class ClassyUsersView(FlaskView):
@route('/<int:id>', strict_slashes=False)
@route('/<int:id>/<username>', strict_slashes=False, endpoint='classy_profile')
def profile(self, id, username=None):
user = models.User.query.get_or_404(id)
if user.clean_username != username:
return redirect(url_for('classy_profile', id=id, username=user.clean_username))
return render_template('profile.html', user=user)
ClassyUsersView.register(app)
У них разные конечные точки, которые необходимо учитывать для url_for
:
>>> app.url_map
Map([<Rule '/classyusers/<id>/<username>' (HEAD, OPTIONS, GET) -> classy_profile>,
<Rule '/user/<id>/<username>' (HEAD, OPTIONS, GET) -> profile>,
<Rule '/classyusers/<id>' (HEAD, OPTIONS, GET) -> ClassyUsersView:profile_1>,
<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
<Rule '/user/<id>' (HEAD, OPTIONS, GET) -> profile>])
Без flask-classy
имя конечной точки является именем функции, но, как вы выяснили, это отличается при использовании classy
, и вы можете либо посмотреть имя конечной точки с помощью url_map()
, либо назначить это на вашем маршруте с помощью @route(..., endpoint='name')
.
меньше переадресаций:
Чтобы ответить на отправленные вами URL-адреса, минимизируя количество переадресаций, вам нужно использовать strict_slashes=False
, это позволит обрабатывать запросы, которые не завершаются с помощью /
, а не перенаправлять их с помощью 301
перенаправлять на свой /
-термированный экземпляр:
@app.route('/user/<int:id>', strict_slashes=False)
@app.route('/user/<int:id>/<username>', strict_slashes=False)
def profile(id, username=None):
user = models.User.query.get_or_404(id)
if user.clean_username != username:
return redirect(url_for('profile', id=id, username=user.clean_username))
return render_template('profile.html', user=user)
вот результат:
>>> client = app.test_client()
>>> def check(url):
... r = client.get(url)
... return r.status, r.headers.get('location')
...
>>> check('/user/123')
('302 FOUND', 'http://localhost/user/123/johndoe')
>>> check('/user/123/')
('302 FOUND', 'http://localhost/user/123/johndoe')
>>> check('/user/123/foo')
('302 FOUND', 'http://localhost/user/123/johndoe')
>>> check('/user/123/johndoe')
('200 OK', None)
>>> check('/user/123/johndoe/')
('200 OK', None)
>>> check('/user/125698')
('404 NOT FOUND', None)
Поведение strict_slashes
:
with strict_slashes=False
URL Redirects/points to # of redirects
===========================================================================
/user/123 302 /user/123/clean_username 1
/user/123/ 302 /user/123/clean_username 1
/user/123/foo 302 /user/123/clean_username 1
/user/123/foo/ 302 /user/123/clean_username 1
/user/123/clean_username 302 /user/123/clean_username 1
/user/123/clean_username/ 200 /user/123/clean_username/ 0
/user/125698 404
with strict_slashes=True (the default)
any non '/'-terminated urls redirect to their '/'-terminated counterpart
URL Redirects/points to # of redirects
===========================================================================
/user/123 301 /user/123/ 2
/user/123/foo 301 /user/123/foo/ 2
/user/123/clean_username 301 /user/123/clean_username/ 1
/user/123/ 302 /user/123/clean_username/ 1
/user/123/foo/ 302 /user/123/clean_username/ 1
/user/123/clean_username/ 200 /user/123/clean_username/ 0
/user/125698 404
example:
"/user/123/foo" not terminated with '/' -> redirects to "/user/123/foo/"
"/user/123/foo/" -> redirects to "/user/123/clean_username/"
Я считаю, что он точно соответствует вашей тестовой матрице:)