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 trialHakim Rachidi
38,490 PointsAlways 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.
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)
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()
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()
]
)
<!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>
{% 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
KRIS NIKOLAISEN
54,972 PointsI 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() %}
Jeff Muday
Treehouse Moderator 28,722 PointsNice 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')
nakalkucing
12,964 Pointsnakalkucing
12,964 PointsHi 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
Hakim Rachidi
38,490 PointsHakim Rachidi
38,490 PointsUsed 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