BuildError: Could not build url for endpoint 'user' with values ['nickname']. Did you forget to specify values ['page', 'username']?

38,645

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)
Share:
38,645
rockets4all
Author by

rockets4all

Updated on July 09, 2022

Comments

  • rockets4all
    rockets4all almost 2 years

    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 -
    
  • rockets4all
    rockets4all almost 7 years
    Thanks for the help, I was looking at an old template in gedit and was editing the wrong code. I was about to go crazy with why i was getting this error even though the code it referenced didn't exist.
  • iFunction
    iFunction over 5 years
    Wish you had left the original template up as it is impossible to follow this thread now as there is no error, it's not possible to see how this was fixed