I am getting the following error when I try to goto index.html on my site. The site was templated from https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-v-user-logins I modified it to take in usernames/passwords and got rid of openid. I went through and replaced nickname in the database with username and somehow it is still referencing it even after I have updated the database. I'm still new to this so please go easy. I searched for how to build url's and can't find anything I'm doing wrong.
BuildError: Could not build url for endpoint 'user' with values ['nickname']. Did you forget to specify values ['page', 'username']?
Here is most of the code to it, let me know and I'll post anything else relevant.
views.py
from flask import render_template, flash, redirect, session, url_for, request, \
g, jsonify
from flask_login import login_user, logout_user, current_user, login_required
from flask_sqlalchemy import get_debug_queries
from flask_babel import gettext
from datetime import datetime
from guess_language import guessLanguage
from app import app, db, lm, babel
from .forms import EditForm, PostForm, SearchForm, RegistrationForm, LoginForm
from .models import User, Post
from .emails import follower_notification
from .translate import microsoft_translate
from config import POSTS_PER_PAGE, MAX_SEARCH_RESULTS, LANGUAGES, \
DATABASE_QUERY_TIMEOUT
@lm.user_loader
def load_user(id):
return User.query.get(int(id))
@babel.localeselector
def get_locale():
return request.accept_languages.best_match(LANGUAGES.keys())
@app.before_request
def before_request():
g.user = current_user
if g.user.is_authenticated:
g.user.last_seen = datetime.utcnow()
db.session.add(g.user)
db.session.commit()
g.search_form = SearchForm()
g.locale = get_locale()
@app.after_request
def after_request(response):
for query in get_debug_queries():
if query.duration >= DATABASE_QUERY_TIMEOUT:
app.logger.warning(
"SLOW QUERY: %s\nParameters: %s\nDuration: %fs\nContext: %s\n" %
(query.statement, query.parameters, query.duration,
query.context))
return response
@app.errorhandler(404)
def not_found_error(error):
return render_template('404.html'), 404
@app.errorhandler(500)
def internal_error(error):
db.session.rollback()
return render_template('500.html'), 500
@app.route('/', methods=['GET', 'POST'])
@app.route('/index', methods=['GET', 'POST'])
@app.route('/index/<int:page>', methods=['GET', 'POST'])
@login_required
def index(page=1):
form = PostForm()
if form.validate_on_submit():
language = guessLanguage(form.post.data)
if language == 'UNKNOWN' or len(language) > 5:
language = ''
post = Post(body=form.post.data, timestamp=datetime.utcnow(),
author=g.user, language=language)
db.session.add(post)
db.session.commit()
flash(gettext('Your post is now live!'))
return redirect(url_for('index'))
posts = g.user.followed_posts().paginate(page, POSTS_PER_PAGE, False)
return render_template('index.html',
title='Home',
form=form,
posts=posts)
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm(request.form)
print("request.form=", request.form, "form.validate=", form.validate())
if request.method == 'POST' and form.validate():
print("BLANK")
print(User.query.filter_by(username=form.username.data).first())
if User.query.filter_by(username=form.username.data).first() == None:
user = User(username=form.username.data)
user.hash_password(form.password.data)
db.session.add(user)
# make the user follow him/herself
db.session.add(user.follow(user))
db.session.commit()
flash('Thanks for registering')
return redirect(url_for('login'))
else:
flash('Username already exists')
return render_template('register.html', form=form)
return render_template('register.html', form=form)
@app.route('/login', methods=['GET', 'POST'])
def login():
if g.user is not None and g.user.is_authenticated:
return redirect(url_for('index'))
form=LoginForm()
if form.validate_on_submit():
session['remember_me'] = form.remember_me.data
user=User.query.filter_by(username=form.username.data).first()
if user and user.verify_password(form.password.data):
if 'remember_me' in session:
remember_me = session['remember_me']
session.pop('remember_me', None)
login_user(user, remember=remember_me)
flash("Logged in sucessfully.")
'''eventually update to add security to redirects
if not is_safe_url(next):
return flask.abort(400)
return redirect(request.args.get('next') or url_for('index'))
'''
return redirect(request.args.get('next') or url_for('index'))
flash("Incorrect username or password")
return render_template('login.html',
title='Sign In',
form=form)
'''
if g.user is not None and g.user.is_authenticated:
return redirect(url_for('index'))
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username).first()
login_user(user)
session['remember_me'] = form.remember_me.data
return render_template('login.html',
title='Sign In',
form=form)
'''
'''
@oid.after_login
def after_login(resp):
if resp.email is None or resp.email == "":
flash(gettext('Invalid login. Please try again.'))
return redirect(url_for('login'))
user = User.query.filter_by(email=resp.email).first()
if user is None:
username = resp.username
if username is None or username == "":
username = resp.email.split('@')[0]
username = User.make_valid_username(username)
username = User.make_unique_username(username)
user = User(username=username, email=resp.email)
db.session.add(user)
db.session.commit()
# make the user follow him/herself
db.session.add(user.follow(user))
db.session.commit()
remember_me = False
if 'remember_me' in session:
remember_me = session['remember_me']
session.pop('remember_me', None)
login_user(user, remember=remember_me)
return redirect(request.args.get('next') or url_for('index'))
'''
@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('index'))
@app.route('/user/<username>')
@app.route('/user/<username>/<int:page>')
@login_required
def user(username, page=1):
user = User.query.filter_by(username=username).first()
if user is None:
flash(gettext('User %(username)s not found.', username=username))
return redirect(url_for('index'))
posts = user.posts.paginate(page, POSTS_PER_PAGE, False)
return render_template('user.html',
user=user,
posts=posts,
title='Your Profile')
@app.route('/mobility', methods=['GET', 'POST'])
@login_required
def mobility():
return render_template('mobility.html')
@app.route('/edit', methods=['GET', 'POST'])
@login_required
def edit():
form = EditForm(g.user.username)
if form.validate_on_submit():
g.user.username = form.username.data
g.user.about_me = form.about_me.data
db.session.add(g.user)
db.session.commit()
flash(gettext('Your changes have been saved.'))
return redirect(url_for('edit'))
elif request.method != "POST":
form.username.data = g.user.username
form.about_me.data = g.user.about_me
return render_template('edit.html', form=form)
@app.route('/follow/<username>')
@login_required
def follow(username):
user = User.query.filter_by(username=username).first()
if user is None:
flash('User %s not found.' % username)
return redirect(url_for('index'))
if user == g.user:
flash(gettext('You can\'t follow yourself!'))
return redirect(url_for('user', username=username))
u = g.user.follow(user)
if u is None:
flash(gettext('Cannot follow %(username)s.', username=username))
return redirect(url_for('user', username=username))
db.session.add(u)
db.session.commit()
flash(gettext('You are now following %(username)s!', username=username))
follower_notification(user, g.user)
return redirect(url_for('user', username=username))
@app.route('/unfollow/<username>')
@login_required
def unfollow(username):
user = User.query.filter_by(username=username).first()
if user is None:
flash('User %s not found.' % username)
return redirect(url_for('index'))
if user == g.user:
flash(gettext('You can\'t unfollow yourself!'))
return redirect(url_for('user', username=username))
u = g.user.unfollow(user)
if u is None:
flash(gettext('Cannot unfollow %(username)s.', username=username))
return redirect(url_for('user', username=username))
db.session.add(u)
db.session.commit()
flash(gettext('You have stopped following %(username)s.',
username=username))
return redirect(url_for('user', username=username))
@app.route('/delete/<int:id>')
@login_required
def delete(id):
post = Post.query.get(id)
if post is None:
flash('Post not found.')
return redirect(url_for('index'))
if post.author.id != g.user.id:
flash('You cannot delete this post.')
return redirect(url_for('index'))
db.session.delete(post)
db.session.commit()
flash('Your post has been deleted.')
return redirect(url_for('index'))
@app.route('/search', methods=['POST'])
@login_required
def search():
if not g.search_form.validate_on_submit():
return redirect(url_for('index'))
return redirect(url_for('search_results', query=g.search_form.search.data))
@app.route('/search_results/<query>')
@login_required
def search_results(query):
results = Post.query.whoosh_search(query, MAX_SEARCH_RESULTS).all()
return render_template('search_results.html',
query=query,
results=results)
@app.route('/translate', methods=['POST'])
@login_required
def translate():
return jsonify({
'text': microsoft_translate(
request.form['text'],
request.form['sourceLang'],
request.form['destLang'])})
models.py
from hashlib import md5
import re
from app import db
from app import app
from config import WHOOSH_ENABLED
from passlib.apps import custom_app_context as pwd_context
import sys
if sys.version_info >= (3, 0):
enable_search = False
else:
enable_search = WHOOSH_ENABLED
if enable_search:
import flask_whooshalchemy
followers = db.Table(
'followers',
db.Column('follower_id', db.Integer, db.ForeignKey('user.id')),
db.Column('followed_id', db.Integer, db.ForeignKey('user.id'))
)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(32), index=True, unique=True)
password_hash = db.Column(db.String(128))
email = db.Column(db.String(120), index=True, unique=True)
posts = db.relationship('Post', backref='author', lazy='dynamic')
about_me = db.Column(db.String(140))
last_seen = db.Column(db.DateTime)
followed = db.relationship('User',
secondary=followers,
primaryjoin=(followers.c.follower_id == id),
secondaryjoin=(followers.c.followed_id == id),
backref=db.backref('followers', lazy='dynamic'),
lazy='dynamic')
def hash_password(self, password):
self.password_hash=pwd_context.encrypt(password)
def verify_password(self, password):
return pwd_context.verify(password, self.password_hash)
@staticmethod
def make_valid_username(username):
return re.sub('[^a-zA-Z0-9_\.]', '', username)
@staticmethod
def make_unique_username(username):
if User.query.filter_by(username=username).first() is None:
return username
version = 2
while True:
new_username = username + str(version)
if User.query.filter_by(username=new_username).first() is None:
break
version += 1
return new_username
@property
def is_authenticated(self):
return True
@property
def is_active(self):
return True
@property
def is_anonymous(self):
return False
def get_id(self):
try:
return unicode(self.id) # python 2
except NameError:
return str(self.id) # python 3
def avatar(self, size):
return 'http://www.gravatar.com/avatar/%s?d=mm&s=%d' % \
(md5(self.email.encode('utf-8')).hexdigest(), size)
def follow(self, user):
if not self.is_following(user):
self.followed.append(user)
return self
def unfollow(self, user):
if self.is_following(user):
self.followed.remove(user)
return self
def is_following(self, user):
return self.followed.filter(
followers.c.followed_id == user.id).count() > 0
def followed_posts(self):
return Post.query.join(
followers, (followers.c.followed_id == Post.user_id)).filter(
followers.c.follower_id == self.id).order_by(
Post.timestamp.desc())
def __repr__(self): # pragma: no cover
return '<User %r>' % (self.username)
class Post(db.Model):
__searchable__ = ['body']
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.String(140))
timestamp = db.Column(db.DateTime)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
language = db.Column(db.String(5))
def __repr__(self): # pragma: no cover
return '<Post %r>' % (self.body)
#if enable_search:
# whooshalchemy.whoosh_index(app, Post)
index.html
<!-- extend base layout -->
{% extends "base.html" %}
{% block content %}
<h1>{{ _('Hi, %(username)s!', username=g.user.username) }}</h1>
{% include 'flash.html' %}
<div class="well">
<form class="form-horizontal" action="" method="post" name="post">
{{ form.hidden_tag() }}
<div class="control-group{% if form.post.errors %} error{% endif %}">
<label class="control-label" for="post">{{ _('Say something:') }}</label>
<div class="controls">
{{ form.post(size=30, maxlength=140) }}
{% for error in form.post.errors %}
<span class="help-inline">[{{ error }}]</span><br>
{% endfor %}
</div>
</div>
<div class="control-group">
<div class="controls">
<input class="btn btn-primary" type="submit" value="{{ _('Post!') }}">
</div>
</div>
</form>
</div>
{% for post in posts.items %}
{% include 'post.html' %}
{% endfor %}
<ul class="pager">
{% if posts.has_prev %}
<li class="previous"><a href="{{ url_for('index', page=posts.prev_num) }}">{{ _('Newer posts') }}</a></li>
{% else %}
<li class="previous disabled"><a href="#">{{ _('Newer posts') }}</a></li>
{% endif %}
{% if posts.has_next %}
<li class="next"><a href="{{ url_for('index', page=posts.next_num) }}">{{ _('Older posts') }}</a></li>
{% else %}
<li class="next disabled"><a href="#">{{ _('Older posts') }}</a></li>
{% endif %}
</ul>
{% endblock %}
post.html
<table class="table table-hover">
<tr>
<td width="70px"><a href="{{ url_for('user', username=post.author.username) }}"><img src="{{ post.author.avatar(70) }}" /></a></td>
<td>
{% autoescape false %}
<p>{{ _('%(username)s said %(when)s:', username='<a href="%s">%s</a>' % (url_for('user', username=post.author.username), post.author.username), when=momentjs(post.timestamp).fromNow()) }}</p>
{% endautoescape %}
<p><strong><span id="post{{ post.id }}">{{ post.body }}</span></strong></p>
{% if post.language != None and post.language != '' and post.language != g.locale %}
<div>
<span id="translation{{ post.id }}">
<a href="javascript:translate('{{ post.language }}', '{{ g.locale }}', '#post{{ post.id }}', '#translation{{ post.id }}', '#loading{{ post.id }}');">{{ _('Translate') }}</a>
</span>
<img id="loading{{ post.id }}" style="display: none" src="/static/img/loading.gif">
</div>
{% endif %}
{% if post.author.id == g.user.id %}
<div><a href="{{ url_for('delete', id = post.id) }}">{{ _('Delete') }}</a></div>
{% endif %}
</td>
</tr>
</table>
forms.py
from flask_wtf import Form
from flask_babel import gettext
from wtforms import StringField, BooleanField, TextAreaField, PasswordField
from wtforms.validators import DataRequired, Length, EqualTo
from .models import User
class LoginForm(Form):
username = StringField('username', validators=[DataRequired()])
password = PasswordField('password', validators=[DataRequired()])
remember_me = BooleanField('remember_me', default=False)
class RegistrationForm(Form):
username=StringField('Username', validators=[Length(min=4, max=25)])
password = PasswordField('Password', validators=[DataRequired(),
EqualTo('confirm', message='Passwords must match')])
confirm = PasswordField('Repeat Password')
remember_me = BooleanField('remember_me', default=False)
class EditForm(Form):
username = StringField('username', validators=[DataRequired()])
about_me = TextAreaField('about_me', validators=[Length(min=0, max=140)])
def __init__(self, original_username, *args, **kwargs):
Form.__init__(self, *args, **kwargs)
self.original_username = original_username
def validate(self):
if not Form.validate(self):
return False
if self.username.data == self.original_username:
return True
if self.username.data != User.make_valid_username(self.username.data):
self.username.errors.append(gettext(
'This username has invalid characters. '
'Please use letters, numbers, dots and underscores only.'))
return False
user = User.query.filter_by(username=self.username.data).first()
if user is not None:
self.username.errors.append(gettext(
'This username is already in use. '
'Please choose another one.'))
return False
return True
class PostForm(Form):
post = StringField('post', validators=[DataRequired()])
class SearchForm(Form):
search = StringField('search', validators=[DataRequired()])
Here is the full error from the console
BuildError: Could not build url for endpoint 'user' with values ['nickname']. Did you forget to specify values ['page', 'username']?
127.0.0.1 - - [19/May/2017 10:30:22] "GET /index?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 -
127.0.0.1 - - [19/May/2017 10:30:22] "GET /index?__debugger__=yes&cmd=resource&f=jquery.js HTTP/1.1" 200 -
127.0.0.1 - - [19/May/2017 10:30:22] "GET /index?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 200 -
127.0.0.1 - - [19/May/2017 10:30:22] "GET /index?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 -
127.0.0.1 - - [19/May/2017 10:30:22] "GET /index?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 -
* Detected change in '/home/jsnyder10/Documents/45/app/views.py', reloading
* Restarting with stat
/home/jsnyder10/Documents/45/flask/local/lib/python2.7/site-packages/flask_whooshalchemy.py:18: ExtDeprecationWarning: Importing flask.ext.sqlalchemy is deprecated, use flask_sqlalchemy instead.
import flask.ext.sqlalchemy as flask_sqlalchemy
* Debugger is active!
* Debugger PIN: 196-025-674
/home/jsnyder10/Documents/45/app/views.py:34: FlaskWTFDeprecationWarning: "flask_wtf.Form" has been renamed to "FlaskForm" and will be removed in 1.0.
g.search_form = SearchForm()
/home/jsnyder10/Documents/45/app/views.py:66: FlaskWTFDeprecationWarning: "flask_wtf.Form" has been renamed to "FlaskForm" and will be removed in 1.0.
form = PostForm()
127.0.0.1 - - [19/May/2017 10:45:14] "GET /index HTTP/1.1" 500 -
Traceback (most recent call last):
File "/home/jsnyder10/Documents/45/flask/lib/python2.7/site-packages/flask/app.py", line 1997, in __call__
return self.wsgi_app(environ, start_response)
File "/home/jsnyder10/Documents/45/flask/lib/python2.7/site-packages/flask/app.py", line 1985, in wsgi_app
response = self.handle_exception(e)
File "/home/jsnyder10/Documents/45/flask/lib/python2.7/site-packages/flask/app.py", line 1540, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/jsnyder10/Documents/45/flask/lib/python2.7/site-packages/flask/app.py", line 1982, in wsgi_app
response = self.full_dispatch_request()
File "/home/jsnyder10/Documents/45/flask/lib/python2.7/site-packages/flask/app.py", line 1614, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/jsnyder10/Documents/45/flask/lib/python2.7/site-packages/flask/app.py", line 1517, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/jsnyder10/Documents/45/flask/lib/python2.7/site-packages/flask/app.py", line 1612, in full_dispatch_request
rv = self.dispatch_request()
File "/home/jsnyder10/Documents/45/flask/lib/python2.7/site-packages/flask/app.py", line 1598, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/jsnyder10/Documents/45/flask/lib/python2.7/site-packages/flask_login/utils.py", line 228, in decorated_view
return func(*args, **kwargs)
File "/home/jsnyder10/Documents/45/app/views.py", line 81, in index
posts=posts)
File "/home/jsnyder10/Documents/45/flask/lib/python2.7/site-packages/flask/templating.py", line 134, in render_template
context, ctx.app)
File "/home/jsnyder10/Documents/45/flask/lib/python2.7/site-packages/flask/templating.py", line 116, in _render
rv = template.render(context)
File "/home/jsnyder10/Documents/45/flask/lib/python2.7/site-packages/jinja2/environment.py", line 1008, in render
return self.environment.handle_exception(exc_info, True)
File "/home/jsnyder10/Documents/45/flask/lib/python2.7/site-packages/jinja2/environment.py", line 780, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/jsnyder10/Documents/45/app/templates/index.html", line 2, in top-level template code
{% extends "base.html" %}
File "/home/jsnyder10/Documents/45/app/templates/base.html", line 63, in top-level template code
{% block content %}{% endblock %}
File "/home/jsnyder10/Documents/45/app/templates/index.html", line 27, in block "content"
{% include 'post.html' %}
File "/home/jsnyder10/Documents/45/app/templates/post.html", line 3, in top-level template code
<td width="70px"><a href="{{ url_for('user', nickname=post.author.nickname) }}"><img src="{{ post.author.avatar(70) }}" /></a></td>
File "/home/jsnyder10/Documents/45/flask/lib/python2.7/site-packages/flask/helpers.py", line 333, in url_for
return appctx.app.handle_url_build_error(error, endpoint, values)
File "/home/jsnyder10/Documents/45/flask/lib/python2.7/site-packages/flask/app.py", line 1805, in handle_url_build_error
reraise(exc_type, exc_value, tb)
File "/home/jsnyder10/Documents/45/flask/lib/python2.7/site-packages/flask/helpers.py", line 323, in url_for
force_external=external)
File "/home/jsnyder10/Documents/45/flask/lib/python2.7/site-packages/werkzeug/routing.py", line 1768, in build
raise BuildError(endpoint, values, method, self)
BuildError: Could not build url for endpoint 'user' with values ['nickname']. Did you forget to specify values ['page', 'username']?
127.0.0.1 - - [19/May/2017 10:45:14] "GET /index?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 -
127.0.0.1 - - [19/May/2017 10:45:14] "GET /index?__debugger__=yes&cmd=resource&f=jquery.js HTTP/1.1" 200 -
127.0.0.1 - - [19/May/2017 10:45:14] "GET /index?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 200 -
127.0.0.1 - - [19/May/2017 10:45:14] "GET /index?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 -
127.0.0.1 - - [19/May/2017 10:45:15] "GET /index?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 -
The route calls for the variable username
to be defined, but you're passing a variable called nickname
in your post.html template.
flask.url_for('user', nickname=post.author.nickname)
needs to be changed to:
flask.url_for('user', username=post.author.nickname)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With