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!

Why am I getting a Key Error when I run app_tests.py?

Traceback (most recent call last):
  File "app_tests.py", line 6, in <module>
    import tacocat
  File "/Users/Ginny/Desktop/Websites/Flask projects/TacoCat/tacocat.py", line 8, in <module>
    import forms
  File "/Users/Ginny/Desktop/Websites/Flask projects/TacoCat/forms.py", line 6, in <module>
    from models import User
  File "/Users/Ginny/Desktop/Websites/Flask projects/TacoCat/models.py", line 35, in <module>
    class Taco(Model):
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/peewee.py", line 4072, in __new__
    cls._meta.prepared()
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/peewee.py", line 3911, in prepared
    field = self.fields[item.lstrip('-')]
KeyError: ''
tacocat.py
import datetime

from flask.ext.bcrypt import generate_password_hash
from flask.ext.login import UserMixin

from peewee import *


DATABASE = SqliteDatabase('tacocat.db')


class User(UserMixin, Model):
    """A taco cat customer"""
    username = CharField(unique=True)
    email = CharField(unique=True)
    password = CharField(max_length=100)
    is_admin = BooleanField(default=False)

    class Meta:
        database = DATABASE

    @classmethod
    def create_user(cls, username, email, password, admin=False):
        try:
            with DATABASE.transaction():
                cls.create(
                    username=username,
                    email=email,
                    password=generate_password_hash(password),
                    is_admin=admin)
        except IntegrityError:
            raise ValueError("User already exists")


class Taco(Model):
    """Taco creation by the customer"""
    timestamp = DateTimeField(default=datetime.datetime.now)
    user = ForeignKeyField(
        rel_model=User,
        related_name='tacos'
    )
    protein = CharField(max_length=100)
    cheese = BooleanField()
    shell = CharField(max_length=100)
    extras = TextField()

    class Meta:
        database = DATABASE
        order_by = ('-timestamp')


def initialize():
    DATABASE.connect()
    DATABASE.create_tables([User, Taco], safe=True)
    DATABASE.close()
models.py
import datetime

from flask.ext.bcrypt import generate_password_hash
from flask.ext.login import UserMixin

from peewee import *


DATABASE = SqliteDatabase('tacocat.db')


class User(UserMixin, Model):
    """A taco cat customer"""
    username = CharField(unique=True)
    email = CharField(unique=True)
    password = CharField(max_length=100)
    is_admin = BooleanField(default=False)

    class Meta:
        database = DATABASE

    @classmethod
    def create_user(cls, username, email, password, admin=False):
        try:
            with DATABASE.transaction():
                cls.create(
                    username=username,
                    email=email,
                    password=generate_password_hash(password),
                    is_admin=admin)
        except IntegrityError:
            raise ValueError("User already exists")


class Taco(Model):
    """Taco creation by the customer"""
    timestamp = DateTimeField(default=datetime.datetime.now)
    user = ForeignKeyField(
        rel_model=User,
        related_name='tacos'
    )
    protein = CharField(max_length=100)
    cheese = BooleanField()
    shell = CharField(max_length=100)
    extras = TextField()

    class Meta:
        database = DATABASE
        order_by = ('-timestamp')


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

from models import User

def name_exists(form, field):
    """Register fails because it is a username that already exists in the database"""
    if User.select().where(User.username == field.data).exists():
        raise ValidationError('User with that name already exists.')


def email_exists(form, field):
    """Register fails because it is an email that already exists in the database"""
    if User.select().where(User.email == field.data).exists():
        raise ValidationError('User with that email already exists.')


class RegisterForm(Form):
    """Creates a form to register a new user"""
    username = StringField(
        'Username',
        validators=[
            DataRequired(),
            Regexp(
                r'^[a-zA-Z0-9_]+$',
                message=("Username should be one word, letters, "
                         "numbers, and underscores only.")
            ),
            name_exists
        ])
    email = StringField(
        'Email',
        validators=[
            DataRequired(),
            Email(),
            email_exists
        ])
    password = PasswordField(
        'Password',
        validators=[
            DataRequired(),
            Length(min=2),
            EqualTo('password2', message='Passwords must match')
        ])
    password2 = PasswordField(
        'ConfirmPassword',
        validators=[DataRequired()]
    )


class LoginForm(Form):
    """Creates a form to log a user in"""
    email = StringField('Email', validators=[DataRequired(), Email()])
    password = PasswordField('Password', validators=[DataRequired()])


class TacoForm(Form):
    """Creates a form to order a taco"""
    protein = StringField("Meat? Chicken? Pork? Veggie?", validator=[DataRequired()])
    cheese = BooleanField("Cheese", default=True)
    shell = StringField("Corn? Wheat? Crispy? Soft?", validator=[DataRequired()])
    extras = TextAreaField("Anything else?", validator=[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">
          <!-- menu goes here -->
            <a href="{{ url_for('register') }}">Sign Up</a>
            <a href="{{ url_for('login') }}">Sign In</a>
            {% if current_user.is_authenticated() %}
            <a href="{{ url_for('create_taco') }}">Create a Tacop</a>
            <a href="{{ url_for('logout') }}">Sign Out</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>
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>
              <!-- taco attributes here -->
              <td>{{ taco.protein }}</td>
              <td>{{ taco.cheese }}</td>
              <td>{{ taco.shell }}</td>
              <td>{{ taco.extras }}</td>
            </tr>
        {% endfor %}
          </tbody>
        </table>
    {% else %}
        <!-- message for missing tacos -->
        <h5>No tacos yet!</h5>
    {% endif %}
{% endblock %}

[edit formating -cf]

1 Answer

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 68,423 Points

I looks like the order_by is incorrect. Try ordering:

class Taco(Model):
    """Taco creation by the customer"""
    timestamp = DateTimeField(default=datetime.datetime.now)
    user = ForeignKeyField(
        rel_model=User,
        related_name='tacos'
    )
    protein = CharField(max_length=100)
    cheese = BooleanField()
    shell = CharField(max_length=100)
    extras = TextField()

    class Meta:
        database = DATABASE
        # Not correct (unless using Django)
        # ordering = ('-timestamp') #<-- changed to "ordering"
        # corrected answer
        order_by = ('-timestamp',) #<-- Adding a comma make a tuple

[Edit: updated answer for peewee (not Django). Doh!]

Hi Chris,

Thanks so much for your help -- changing "order_by" to "ordering" did get rid of my KeyError.

Quick Question though: in the workspaces for our Social Media App, the wording for this code was "order_by" -- why the change here?

class Post(Model):
    """Posts created by the User"""
    timestamp = DateTimeField(default=datetime.datetime.now)
    user = ForeignKeyField(
        rel_model=User,
        related_name='posts'
    )
    content = TextField()

    class Meta:
        database = DATABASE
        order_by = ('-timestamp',)
Chris Freeman
Chris Freeman
Treehouse Moderator 68,423 Points

Right! The actual solution is closer to your original code: Add a comma to make it a tuple! Without the comma it's just a string and order_by expects a list or a tuple. So try:

    class Meta:
        database = DATABASE
        order_by = ('-timestamp',) #<-- Adding a comma make a tuple

I've changed my answer above to reflect this change. My previous answer using ordering was based on Django, not peewee. Oops!

RIGHT! I now remember Kenneth making a big deal out of the tuple in the video. Doh!

Ordering worked in the short term, though, and got me past that error so that I could at least run the tests and pass the challenge, so thank you again for that.