Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Build a Social Network with Flask Tacocat Challenge The Challenge

Oziel Perez
Oziel Perez
61,321 Points

Flask app fails to log out, show the logout screen, and create a taco

Ok so After 2+ weeks of trying to get this to work, I got this challenge down to 3 Failures left, all of which I believe are intertwined with one possible error. The failures are as follows:

======================================================================

FAIL: test_taco_create (main.TacoViewsTestCase)

Traceback (most recent call last):
File "app_tests.py", line 145, in test_taco_create
self.assertEqual(rv.location, 'http://localhost/')
AssertionError: 'http://localhost/login?next=%2Ftaco' != 'http://localhost/'

======================================================================

FAIL: test_logged_out_menu (main.UserViewsTestCase)

Traceback (most recent call last):
File "app_tests.py", line 113, in test_logged_out_menu
self.assertIn("sign up", rv.get_data(as_text=True).lower())
AssertionError: 'sign up' not found in '<!doctype html>\n<html>\n <head>\n <title>tacocat</title>\n <link re l="stylesheet" href="/static/css/normalize.css">\n <link rel="stylesheet" href="/static/css/skeleton.css">\n
<link rel="stylesheet" href="/static/css/tacocat.css">\n </head>\n <body>\n \n \n \n\n <div class="co ntainer">\n <div class="row">\n <div class="u-full-width">\n <nav class="menu">\n \ n <a href="/taco">add a new taco</a>\n <a href="/logout">log out</a>\n \n </nav>\n \n<h2>tacos</h2>\n\n <p>no tacos yet</p>\n \n\n </div>\n </div>\n <footer>\n <p>an mvp web app made with flask on <a href="http://teamtreehouse.com">treehouse</a>.</p>\n </footer>\n </div>\n </body>\n</html>'

======================================================================

FAIL: test_logout (main.UserViewsTestCase)

Traceback (most recent call last):
File "app_tests.py", line 109, in test_logout
self.assertEqual(rv.location, 'http://localhost/')
AssertionError: 'http://localhost/login?next=%2Flogout' != 'http://localhost/'

... so creating a taco and logging out don't work, and I could probably see why, as it requires that the user be logged in. Also, to see the logged-out menu (sign up, log in) would also be connected with this because the user was never able to log in in the first place. The funny thing is that when I test this in my own environment outside treehouse, I register the user, the I log in, but as soon as it redirects me to the home page, it looks like I logged in because of the flash message, but in fact, the user never got logged in to begin with, so I never see the logged in menu (add taco, log out), so I don't know how that portion passed. After some debugging, it turned out that I kept getting an AnonymousUserMixin object instead of the user. It also makes sense why current_user.is_activated returns false. So because of that, I never actually log in, tacos can't be posted, it's impossible to log out, and the post-check for a log out menu fails. does anyone know what could be wrong? Here's the 2 relevant files:

from flask import Flask, render_template, redirect, flash, g, abort, url_for
from flask_login import LoginManager, login_user, logout_user, current_user, login_required
from flask_bcrypt import check_password_hash
import models, forms

app = Flask(__name__);
app.secret_key = "p9fihq2u94fhuhefujkqnwfu9hwfkjaefugqbfiubhiudhjandiu";

login_manager = LoginManager();
login_manager.init_app(app);
login_manager.login_view = "login";

@login_manager.user_loader
def load_user(user):
    try:
        return models.User.get(models.User.email == user);
    except models.DoesNotExist:
        return None;

@app.before_request
def before():
    g.db = models.db
    g.db.connect();
    g.user = current_user;

@app.after_request
def after(response):
    g.db.close();
    return response;

@app.route("/")
def index():
    user = g.user._get_current_object();
    #tacos = models.User.select().join(models.Taco, on = models.Taco.user).where(models.Taco.user ** user);
    tacos = models.Taco.select().where(models.Taco.user ** user);
    return render_template("index.html", tacos = tacos, message = "No tacos yet");

@app.route("/register", methods=["GET", "POST"])
def register():
    form = forms.RegistrationForm();
    if form.validate_on_submit():
        try:
            models.User.create_user(
                email = form.email.data.strip(),
                password = form.password.data.strip()
            );
            flash("Registration successful, login to continue!", "success");
            return redirect(url_for("index"));
        except ValueError as e:
            flash(e, "error");
    return render_template("register.html", form = form);  

@app.route("/login", methods = ["GET", "POST"])
def login():
    form = forms.LoginForm();
    if form.validate_on_submit():
        try:
            user = models.User.get(models.User.email ** form.email.data.strip());
            if check_password_hash(user.password, form.password.data.strip()):
                login_user(user);
                flash("Welcome Back!", "success");
                return redirect(url_for("index"));
            else:
                flash("Username or password is not correct", "error");
        except models.DoesNotExist:
            flash("Username or password is incorrect", "error");
    return render_template("login.html", form = form);

@app.route("/logout")
@login_required
def logout():
    logout_user();
    return redirect(url_for("index"));

@app.route("/taco", methods = ["GET", "POST"])
@login_required
def taco():
    form = forms.Post();
    if form.validate_on_submit():
        models.Post.create(
            user = g.user._get_current_object(),
            protein = form.protein.data.strip(),
            shell = form.shell.data.strip(),
            cheese = form.cheese.data.strip(),
            extras = form.extras.data.strip()
        );
        return redirect(url_for("index"));
    flash("Unable to post taco", "error");
    return render_template("taco.html", form = form);


if __name__ == "__main__":
    app.run(host = "127.0.0.1", debug = True, port = 3000);
<!doctype html>
<html>
  <head>
    <title>Tacocat</title>
    <link rel="stylesheet" href="/static/css/normalize.css">
    <link rel="stylesheet" href="/static/css/skeleton.css">
    <link rel="stylesheet" href="/static/css/tacocat.css">
  </head>
  <body>
    {% with messages=get_flashed_messages() %}
    {% if messages %}
        <div class="messages">
          {% for message in messages %}
          <div class="message">
            {{ message }}
          </div>
          {% endfor %}
        </div>
    {% endif %}
    {% endwith %}

    <div class="container">
      <div class="row">
        <div class="u-full-width">
          <nav class="menu">
            {% if current_user.is_authenticated %}
                <a href="{{ url_for('taco') }}">Add a New Taco</a>
                <a href="{{ url_for('logout') }}">Log Out</a>
            {% else %}
                <a href="{{ url_for('register') }}">Sign Up</a>
                <a href="{{ url_for('login') }}">Log In</a>
            {% endif %}
          </nav>
          {% block content %}{% endblock %}
        </div>
      </div>
      <footer>
        <p>An MVP web app made with Flask on <a href="http://teamtreehouse.com">Treehouse</a>.</p>
      </footer>
    </div>
  </body>
</html>

2 Answers

Ryan S
Ryan S
27,276 Points

Hi Oziel,

This is a tough challenge and tough to debug. I've been playing around with your code and all the views seem good. One thing that I noticed though is that you don't call the initialize() function from models.py in the if __name__ == '__main__': statement. I'm not sure if you are doing it some other way but it doesn't look like you are connecting to the database and creating the tables. Maybe that is why you can't create a taco or log in?

Good Luck

Oziel Perez
Oziel Perez
61,321 Points

I tried your suggestion and it didn't work, so I don't believe that was the issue. I tried using @login_required on the index view and sure enough, it redirects me to the login page (according to login_manager.login_view) and when I try to log in, I get 2 flash messages "Welcome back" (which occurs if you successfully validate your login form) and "please log in to continue", which happens after being redirected. So after login, I pretty much get redirected back to the same login page because I'm not logged in at all, confirming my findings that I just get an anonymoususermixin object instead of the user that needs to be logged in.

Ryan S
Ryan S
27,276 Points

Another thing I just noticed is that in your load_user view, you are trying to get the User email instead of the User id. If you look at the documentation, @login_manager.user_loader and the load_user function can only take the unicode id of a user, and won't work with any other attribute. Maybe that is the issue?

Oziel Perez
Oziel Perez
61,321 Points

I think you're on to something! I just remembered that in a separate project I used to follow along during the course, I had to manually override the get_id method that comes with UserMixin (because I was using a database table that didn't have an id column). Now because of adding that, I have reduced it to one Failure and one Error. The fail is that I still can't see the "logged out" menu and the error is that the models.py file doesn't have Post, but the latter is super easy, I just need to change every instance of models.Post to models.Taco. Hopefully I solve this challenge in a few minutes....

Oziel Perez
Oziel Perez
61,321 Points

Yes! it worked. So changing email to id in the user loader wasn't the problem, and I should have known cause that's how I did it in the course, but it was the fact that I forgot to override get_id(), which was the same problem I had in the course for several days. After that, I just had to fix the error with models.Post being changed to models.Taco and then changing current_user.is_authenticated to current_user.is_authenticated(). It depends on your python environment if you need parentheses or not; the challenge did require them. Thanks for your help!

Ryan S
Ryan S
27,276 Points

Glad to hear you got it solved! It's an interesting challenge for sure, tricky to debug. And yeah I noticed the same thing regarding the parentheses with .is_authenticated in the challenge. It would probably be worthwhile for that to be updated considering they make it clear several times not to use them.