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 Tacocat!

Always getting 'Try again' message

All tests given by Kenneth passed but still I get 'Try again' in the challenge, which is not very helpful. App works as expected in end-to-end testing.

tacocat.py
import flask
from flask import request, url_for, render_template, redirect, flash, g
from flask_login import login_required, LoginManager, login_user, current_user, logout_user
from flask_bcrypt import check_password_hash

import models
import forms

HOST = '0.0.0.0'
PORT = 8080
DEBUG = True
app = flask.Flask(__name__)
app.secret_key = "asdf678as6df8a69s876asdf896asdf87"

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

@login_manager.user_loader
def user_loader(userid):
    try:
        return models.User.get(models.User.id == int(userid))
    except models.DoesNotExist:
        return None
    except ValueError:
        return None


@app.before_request
def before():
    g.DATABASE = models.DATABASE
    g.DATABASE.connect()

@app.after_request
def after(request):
    g.DATABASE.close()
    return request




# ===============================
# Routes
# ===============================


@app.route('/')
def index():
    tacos = models.Taco.select()
    return render_template('index.html', tacos = tacos)

@app.route('/taco', methods=['GET', 'POST'])
@login_required
def taco():
    form = forms.TacoForm()
    if form.validate_on_submit():

        models.Taco.create(
            user =  current_user._get_current_object(),
            protein = form.protein.data,
            shell = form.shell.data,
            cheese = form.cheese.data,
            extras = form.extras.data
        )
        return redirect(url_for('index'))
    return render_template('taco.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)
        except models.DoesNotExist:
            form.email.errors.append("User with this email does not exist")
        else:
            if check_password_hash(user.password, form.password.data):
                login_user(user)
                return redirect(url_for('index'))
            else:
                form.password.errors.append("Password is incorrect")
    return render_template('login.html', form=form)

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = forms.RegisterForm()
    if form.validate_on_submit():
        try:
            user = models.User.create_user(
                email = form.email.data,
                password = form.password.data
            )
        except ValueError:
            # Bad request
            form.email.errors.append("Email already exists")
        else:
            login_user(user)
            return redirect(url_for("index"))
    return render_template('register.html', form=form)

@app.route('/logout', methods=['GET', 'POST'])
@login_required
def logout():
    logout_user()
    return redirect(url_for('index'))



if __name__ == '__main__':
    models.initialize()

    #app.run(host=HOST, port=PORT, debug=DEBUG)
models.py
from peewee import *
from flask_login import UserMixin
from flask_bcrypt import check_password_hash, generate_password_hash

DATABASE = SqliteDatabase('taco.db')

class BaseModel(Model):
    class Meta:
        database = DATABASE

class User(UserMixin, BaseModel):
    email = CharField(unique=True)
    password = CharField()

    @classmethod
    def create_user(cls, email, password):
        try:
            user = User.create(
                email = email,
                password = generate_password_hash(password, rounds=10)
            )
        except IntegrityError:
            raise ValueError('Email already exists')
        else:
            return user



class Taco(BaseModel):
    user = ForeignKeyField(User, related_name="tacos")
    protein = TextField()
    shell = TextField()
    cheese = BooleanField()
    extras = TextField()


def initialize():
    DATABASE.connect()
    DATABASE.drop_tables([User, Taco], safe=True)
    DATABASE.create_tables([User, Taco], safe=True)
    DATABASE.close()
forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, BooleanField, PasswordField
from wtforms.validators import DataRequired, Length, Email, EqualTo


class TacoForm(FlaskForm):
    protein = StringField(
        "Protein"
    )

    cheese = BooleanField(
        "Cheese"
    )

    shell = StringField(
        "Shell"
    )

    extras = StringField(
        "Extras"
    )


class LoginForm(FlaskForm):
    email = StringField(
        "Email",
        validators=[
            Email("Has to be an Email"),
            DataRequired()
        ]
    )

    password = PasswordField(
        "Password",
        validators=[
            DataRequired()
        ]
    )



class RegisterForm(FlaskForm):
    email = StringField(
        "Email",
        validators=[
            Email("Has to be an Email")
        ]
    )

    password = PasswordField(
        "Password",
        validators=[
            DataRequired(),
            EqualTo("password2")
        ]
    )

    password2 = PasswordField(
        "Confirm Password", 
        validators=[
            DataRequired()
        ]
    )
templates/layout.html
<!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 %}
            <div class="row">
                <form action="{{ url_for('logout') }}" method="POST">
                  <input type="submit" value="Log out">
                  <a href="{{ url_for('taco') }}">Add a new taco</a>
                </form>
            </div>

            {% else %}
            <a href="{{ url_for('login') }}">Log in</a>
            <a href="{{ url_for('register') }}">Sign up</a>
            {% endif %}
          </nav>
          {% block content %}{% endblock %}
        </div>
      </div>
      <footer>
        <p>An MVP web app made with Flask by Hakim.</p>
      </footer>
    </div>
  </body>
</html>
templates/index.html
{% extends 'layout.html' %}

{% block content %}
<h2>Tacos</h2>
  {% if tacos.count() %}
    <table class="u-full-width">
      <thead>
        <tr>
          <th>Protein</th>
          <th>Cheese?</th>
          <th>Shell</th>
          <th>Extras</th>
        </tr>
      </thead>
      <tbody>
    {% for taco in tacos %}
        <tr>
          <td>{{taco.protein or '-'}}</td> 
          <td>{{taco.cheese}}</td> 
          <td>{{taco.shell}}</td> 
          <td>{{taco.extras}}</td> 
        </tr>
    {% endfor %}
      </tbody>
    </table>
  {% else %}
  <h2>No tacos yet</h2>
  {% endif %}
{% endblock %}

2 Answers

I tried your code in a workspace and had two issues:

(1) An import error

 File "/home/treehouse/workspace/forms.py", line 1, in <module>                                 
    from flask_wtf import FlaskForm                                                              
ImportError: cannot import name 'FlaskForm'    

I changed FlaskForm to Form

(2) On line 26 of layout.html you have

{% if current_user.is_authenticated %}

it should be

{% if current_user.is_authenticated() %}
nakalkucing
nakalkucing
12,964 Points

Hi KRIS NIKOLAISEN! I guess I should test three times before I speak! ;) I have now deleted my misguiding post. Eventually, (after several tests) I came to the same conclusion as you have. Thank you for a clear answer! :)

Best, Nakal

Used to run those scripts locally in python 3.7 with the lastest versions of all the packages, but they seem to test the code from the challenges in the same old vms as workspaces.

Thanks

Jeff Muday
MOD
Jeff Muday
Treehouse Moderator 28,716 Points

Nice work and congratulations on getting to the end of the course-- the Social Taco app is really full-featured. When you have the app fully working, you would want to include this in your portfolio!

I agree with Nakalkucing, the RegisterForm class is required to pass the unittest of "app_tests.py" Also worth noting, you have to modify the app_tests.py to match the base URL of the app (in my case it was http://localhost/ using local testing environment) and will be different if you are running it on Treehouse WorkSpaces!

When the unittest does a test registration, it looks to make sure it completes and redirects to the top level.

# partial excerpt from app_test.py
class UserViewsTestCase(ViewTestCase):
    def test_registration(self):
        data = {
            'email': 'test@example.com',
            'password': 'password',
            'password2': 'password'
        }
        with test_database(TEST_DB, (User,)):
            rv = self.app.post(
                '/register',
                data=data)
            self.assertEqual(rv.status_code, 302)
            self.assertEqual(rv.location, 'http://localhost/')

When the "register" route is called by the unit test, your code will fail:

@app.route('/register', methods=['GET', 'POST'])
def register():

    # here is the failure point
    form = forms.RegisterForm()
    if form.validate_on_submit():
        try:
            user = models.User.create_user(
                email = form.email.data,
                password = form.password.data
            )
        except ValueError:
            # Bad request
            form.email.errors.append("Email already exists")
        else:
            login_user(user)
            return redirect(url_for("index"))
    return render_template('register.html', form=form)

Just in case you need a hint, my "RegisterForm" code is below--

class RegisterForm(Form):
    email = StringField('Email', validators=[DataRequired(), Email(), email_exists])
    password = PasswordField('Password', validators=[DataRequired(), Length(min=2), EqualTo('password2', message='Password must match')])
    password2 = PasswordField('Confirm',)
    submit = SubmitField('Register')