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 trialKiefer Jones
4,401 PointsYou don't need to call user.followers they are already querysets.
I've read through some of the other answers here that say to remove the parenthesis after followers/following but that doesn't seem to work for me. Not really sure what this wants, it's very unclear.
import datetime
from flask import Flask, g, render_template, flash, redirect, url_for
from flask.ext.bcrypt import check_password_hash
from flask.ext.login import LoginManager, login_user, current_user, login_required, logout_user
import forms
import models
app = Flask(__name__)
app.secret_key = 'this is our super secret key. do not share it with anyone!'
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
@login_manager.user_loader
def load_user(userid):
try:
return models.User.select().where(
models.User.id == int(userid)
).get()
except models.DoesNotExist:
return None
@app.before_request
def before_request():
g.db = models.DATABASE
g.db.connect()
g.user = current_user
@app.after_request
def after_request(response):
g.db.close()
return response
@app.route('/register', methods=('GET', 'POST'))
def register():
form = forms.SignUpInForm()
if form.validate_on_submit():
models.User.new(
email=form.email.data,
password=form.password.data
)
flash("Thanks for registering!")
return render_template('register.html', form=form)
@app.route('/login', methods=('GET', 'POST'))
def login():
form = forms.SignUpInForm()
if form.validate_on_submit():
try:
user = models.User.get(
models.User.email == form.email.data
)
if check_password_hash(user.password, form.password.data):
login_user(user)
flash("You're now logged in!")
else:
flash("No user with that email/password combo")
except models.DoesNotExist:
flash("No user with that email/password combo")
return render_template('register.html', form=form)
@app.route('/secret')
@login_required
def secret():
return "I should only be visible to logged-in users"
@app.route('/logout')
def logout():
logout_user()
return redirect(url_for('login'))
@app.route('/')
def index():
return render_template('index.html')
@app.route('/order', methods=('GET', 'POST'))
def order_lunch():
form = forms.LunchOrderForm()
if form.validate_on_submit():
models.LunchOrder.create(
user=g.user._get_current_object(),
date=form.date.data,
order=form.order.data.strip()
)
return render_template('lunch.html', form=form)
@app.route('/today')
@login_required
def today():
order = models.LunchOrder.select().where(
models.LunchOrder.date == datetime.date.today() &
models.LunchOrder.user == g.user._get_current_object()
).get()
return render_template('today.html', order=order)
@app.route('/cancel_order/<int:order_id>')
@login_required
def cancel_order(order_id):
try:
order = models.LunchOrder.select().where(
id=order_id,
user=g.user._get_current_object()
).get()
except models.DoesNotExist:
pass
else:
order.delete_instance()
return redirect(url_for('index'))
@app.route('/follow/<int:user_id>')
@login_required
def follow(user_id):
try:
user = models.User.get(
models.User.id == user_id
)
models.Relationship.create(
from_user=g.user._get_current_object(),
to_user=user
)
except (models.DoesNotExist, models.IntegrityError):
pass
return redirect(url_for('index'))
@app.route('/unfollow/<int:user_id>')
@login_required
def unfollow(user_id):
try:
user = models.User.get(
models.User.id == user_id
)
models.Relationship.get(
models.Relationship.from_user==g.user._get_current_object(),
models.Relationship.to_user==user
).delete_instance()
except (models.DoesNotExist, models.IntegrityError):
pass
return redirect(url_for('index'))
@app.route('/profile/<int:user_id>')
def profile(user_id):
user = models.User.select().where(
models.User.id == user_id
).get()
return render_template('profile.html', user=user)
import datetime
from flask.ext.bcrypt import generate_password_hash
from flask.ext.login import UserMixin
from peewee import *
DATABASE = SqliteDatabase(':memory:')
class User(UserMixin, Model):
email = CharField(unique=True)
password = CharField(max_length=100)
join_date = DateTimeField(default=datetime.datetime.now)
bio = CharField(default='')
class Meta:
database = DATABASE
@property
def following(self):
return (
User
.select()
.join(Relationship, on=Relationship.to_user)
.where(Relationship.from_user == self)
)
@property
def followers(self):
return (
User
.select()
.join(Relationship, on=Relationship.from_user)
.where(Relationship.to_user == self)
)
@classmethod
def new(cls, email, password):
cls.create(
email=email,
password=generate_password_hash(password)
)
class LunchOrder(Model):
order = TextField()
date = DateField()
user = ForeignKeyField(User, related_name="orders")
class Relationship(Model):
from_user = ForeignKeyField(User, related_name="relationships")
to_user = ForeignKeyField(User, related_name="related_to")
created_at = DateTimeField(default=datetime.datetime.now)
class Meta:
database = DATABASE
indexes = (
(('from_user', 'to_user'), True),
)
def initialize():
DATABASE.connect()
DATABASE.create_tables([User, LunchOrder], safe=True)
DATABASE.close()
{% extends "layout.html" %}
{% from "macro.html" import hide_email %}
{% block content %}
<h1>{{ hide_email(user) }}</h1>
<dl>
<dt>Lunches:</dt>
<dd>{{ user.orders().count() }}</dd>
<dt>Followers:</dt>
<dd>{{ user.followers.count() }}</dd>
<dt>Following:</dt>
<dd>{{ user.following.count() }}</dd>
</dl>
{% endblock %}
1 Answer
Chris Freeman
Treehouse Moderator 68,428 PointsThe error message is misleading. The error is actually with the order
line:
<dl>
<dt>Lunches:</dt>
<dd>{{ user.orders.count() }}</dd> {# remove () after 'orders' #}
<dt>Followers:</dt>
<dd>{{ user.followers.count() }}</dd>
<dt>Following:</dt>
<dd>{{ user.following.count() }}</dd>
</dl>
Kenneth Love: Can the challenge error warning be refined in this case?
Kiefer Jones
4,401 PointsKiefer Jones
4,401 PointsGot it, Thanks again Chris.
Kenneth Love
Treehouse Guest TeacherKenneth Love
Treehouse Guest TeacherYeah, that is a bad error message. I'll see what I can do about it. It's currently confusing the heck out of me so wish me luck.
EDIT:
OK, updated as best I can due to how the processing of the templates happens.
Brendan Whiting
Front End Web Development Techdegree Graduate 84,738 PointsBrendan Whiting
Front End Web Development Techdegree Graduate 84,738 PointsWould you mind clarifying a few things:
1) If I'm following correctly, we don't use the parentheses because we've decorated the methods with @property. Is the purpose of this decorator just for the convenience of not typing "()"?
2) Where does user.orders come from? I don't see that property (or method decorated as property) defined alongside followers and following.
3) What is a queryset?
Chris Freeman
Treehouse Moderator 68,428 PointsChris Freeman
Treehouse Moderator 68,428 Points1) If I'm following correctly, we don't use the parentheses because we've decorated the methods with @property. Is the purpose of this decorator just for the convenience of not typing "()"?
Using the
@property
decorator establishes two things: It makes the name of the function a class attribute (accessible viauser_instance.follows
, and it establishes this function as the "getter" method for accessing this attribute. So accessing the attribute.follows
actually executes the functionfollows()
. See this example on property usage.2) Where does user.orders come from? I don't see that property (or method decorated as property) defined alongside followers and following.
user.orders
is created from theForiegnKey
definition in the classLunchOrder
:The
related_name
argument sets the reverse relationship toLunchOrder
fromUser
asuser.orders
3) What is a queryset?
Flask uses the term
Query
, but many programmers used the termQueryset
borrowed from the Django framework.From StackOverflow:
A django queryset is like its name says, basically a collection of (sql) queries, Print
some_queryset.query
will show you the sql query generated from your django filter calls.Since querysets are lazy, the database query isn't done immediately, but only when needed - when the queryset is evaluated. This happens for example if you call its str method when you print it, if you would call list() on it, or, what happens mostly, you iterate over it (for post in b..). This lazyness should save you from doing unnecessary queries and also allows you to chain querysets and filters for example (you can filter a queryset as often as you want to).
Brendan Whiting
Front End Web Development Techdegree Graduate 84,738 PointsBrendan Whiting
Front End Web Development Techdegree Graduate 84,738 PointsHow does it know by looking at the user object that it has a property called orders without looking at LunchOrder? Or does that line of code in LunchOrder go and modify the User object to give it that property?
Kenneth Love
Treehouse Guest TeacherKenneth Love
Treehouse Guest TeacherYeah, basically. Assuming Peewee works like Django (I haven't read all of the source code yet), all of the models are parsed at startup and then creates attributes on models with relations using the relation name.
Chris Freeman
Treehouse Moderator 68,428 PointsChris Freeman
Treehouse Moderator 68,428 PointsBrendan,
How does it know by looking at the user object that it has a property called orders without looking at LunchOrder? Or does that line of code in LunchOrder go and modify the User object to give it that property?
Great questions!. If you were to inspect the database, you would not see a column for "order", "relationships", or "related_to" in the User table. As an experiment, I moved
LunchOrder
andRelationships
into their own files (lunchorder.py and relationship.py, respectively). In the interactive shell I can then inspect theUser
class as the other classes are imported:Brendan Whiting
Front End Web Development Techdegree Graduate 84,738 PointsBrendan Whiting
Front End Web Development Techdegree Graduate 84,738 PointsThank you guys!!! Very informative.