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

Flask, Build a Social Network, Taking Names' section, Challenge: Form View

Challenge Task 3 of 3

Finally, update the register() view so that the form is validated on submission. If it's valid, use the models.User.new() method to create a new User from the form data and flash the message "Thanks for registering!". You'll need to import flash().

Link to Challenge:

http://teamtreehouse.com/library/build-a-social-network-with-flask/takin-names/form-view

I got through the first challenge with:

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

Then for the second challenge I had to change the import statement to:

from flask import Flask, render_template, g

..then use this code for the def register():

@app.route('/register', methods=('GET', 'POST'))
def register():
    form = forms.SignUpForm()
    return render_template('register.html', form=form)

That got me past the first two challenges, then comes the hardest part, part 3 (see above for challenge question).

So what I did for the third challenge..first off I changed the import statement to:

from flask import Flask, render_template, flash, g

Then for the def register() I updated it to:

@app.route('/register', methods=('GET', 'POST'))
def register():
    form = forms.SignUpForm()
    flash("Thanks for registering!", "success")
    if form.validate_on_submit():
      models.User.new(
            username=form.username.data,
            email=form.email.data,
            password=form.password.data
      )
    return render_template('register.html', form=form)

..but it gives me the error:

Bummer! Didn't get a 200 at '/register'.

..with this Preview button Output text:

Traceback (most recent call last): File "bd6ed656-a2c2-4fb2-bb7c-71d4b6f37776.py", line 163, in print(Template(output_template).render({"defined_vars": defined_vars, "test_output": test_output})) File "/usr/local/pyenv/versions/3.4.1/lib/python3.4/site-packages/jinja2/environment.py", line 969, in render return self.environment.handle_exception(exc_info, True) File "/usr/local/pyenv/versions/3.4.1/lib/python3.4/site-packages/jinja2/environment.py", line 742, in handle_exception reraise(exc_type, exc_value, tb) File "/usr/local/pyenv/versions/3.4.1/lib/python3.4/site-packages/jinja2/_compat.py", line 36, in reraise raise value.with_traceback(tb) File "

The only thing I can figure out from the above Output text message is that somehow the 'return render_template' line isn't working (maybe).

Also tried using 'models.User.create_user(' instead of 'models.User.new('

Also tried adding the line:

 return redirect(url_for('index'))

before the return render_template line, but it made no difference..

Also tried putting the 'flash("Thanks.. line inside the 'models.User.new(' parenthesis (as well as a bunch of other different variations), but couldn't find the magic code to pass.

It's probably something else that's different from 'app.py' code in the Workspace example or the code presented in the Login View video, but I don't know what..

8 Answers

For those of you getting the non-200 response, if you look at at the User class in models.py, you'll notice that User() has a class method, new(), that takes two arguments: email and password. You'll just need to get the email and password data from the forms and then voila!

Also, don't forget to import render_template() and flash() from flask.

from flask import Flask, g, render_template, flash
from flask.ext.login import LoginManager


@app.route('/register', methods=('GET', 'POST'))
def register():
    form = forms.SignUpForm()
    if form.validate_on_submit():
        models.User.new(form.email.data, form.password.data)
        flash("Thanks for registering!")
    return render_template('register.html', form=form)
Gavin Ralston
Gavin Ralston
28,770 Points

The thing to remember here, (and it becomes more clear later on) is that in the challenges for this course you're also building an app, but it's a different one. Same principles, but different models.

In the challenge editor, take a look and see if any other tabs are available (like forms.py or index.html) and see if you can figure out what variables you need to pass in.

Chances are good you're getting a non-200 response because the attributes you're passing to the model are wrong.

    if form.validate_on_submit():
          models.User.new(
                username=form.username.data,
                email=form.email.data,
                password=form.password.data
           )  # if these attributes are wrong...
     # this SHOULD happen regardless, but...
     return render_template('register.html', form=form)

So you're validating on submit, all right, the form verified it for you, but then you start trying to assign username to a model that doesn't have a username attribute, and Python pukes and Flask starts getting sick too and then it's like a pie eating contest and your function brought the castor oil and eggs

jamie tam
jamie tam
2,534 Points

Great response thanks man!!

Hi Gavin,

I definitely agree with you when you said:

I think it would be so helpful if when you passed a code challenge it was retained so you could go back and look at it later.

So far no Flask or Django epiphanies...I agree the instructor should have spend more time going over how Flask possibly relates to the MVC (or MTV) software architectural patterns


For instance, if you combine Flask with ORM (Object-relational mapping) software like SQLAlchemy does it align it more closely with a classic model view controller paradigm?

.

Here's a few possibly related StackOverFlow threads:

http://stackoverflow.com/questions/8066199/is-flask-an-mvc-or-mtv

http://stackoverflow.com/questions/12547206/flask-framework-mvc-pattern

.

An FAQ question regarding Django being "MVC":

https://docs.djangoproject.com/en/dev/faq/general/#django-appears-to-be-a-mvc-framework-but-you-call-the-controller-the-view-and-the-view-the-template-how-come-you-don-t-use-the-standard-names


A flask-mvc github I found:

https://github.com/funkenstein/flask-mvc


The whole Jinja2 "template inheritance" thing was just confusing no matter how many times I watch this video:

https://teamtreehouse.com/library/flask-basics/templates-and-static-files/template-inheritance


I keep wishing for some 10,000 mile high overview of how Flask (the micro-framework) can be used with other software pieces (packages?)

I know Kenneth is not going to go into every single piece of code out there that can interact with Flask but please..maybe even a quick cloud bubble diagram of what "surrounds" flask in terms of interaction possibilities?


What about REST-ful API extensions for Flask?

Some links I found:

http://blog.miguelgrinberg.com/post/designing-a-restful-api-with-python-and-flask

https://github.com/vinta/awesome-python#restful-api

http://flask-restful.readthedocs.org/en/0.3.2/

Flask in combination with (or using) Django's REST-ful API:

http://www.flaskapi.org/

There is so much Flask related info out on the internet and this course just seems to want me to stare down a pinhole tube at what they want me to see..

It's frustrating.

This is the code you are looking for ``` @app.route('/register', methods=('GET', 'POST')) def register(): form = forms.SignUpForm() if form.validate_on_submit(): user = models.User.new(email=form.email.data, password=form.password.data) flash("Thanks for registering!") return render_template('register.html', form=form)

Hi Gavin,

Thanks for trying to help.

I do have two other tabs available:

'models.py' and 'forms.py'


Here's the code found in each of those tabs:

models.py

import datetime

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

DATABASE = SqliteDatabase(':memory:')


class User(Model):
    email = CharField(unique=True)
    password = CharField(max_length=100)
    join_date = DateTimeField(default=datetime.datetime.now)
    bio = CharField(default='')

    class Meta:
        database = DATABASE

    @classmethod
    def new(cls, email, password):
        cls.create(
            email=email,
            password=generate_password_hash(password)
        )


def initialize():
    DATABASE.connect()
    DATABASE.create_tables([User], safe=True)
    DATABASE.close()

forms.py

from flask_wtf import Form
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired, Email, Length


class SignUpForm(Form):
    email = StringField(validators=[DataRequired(), Email()])
    password = PasswordField(validators=[DataRequired(), Length(min=8)])

Then you said:

Chances are good you're getting a non-200 response because the attributes you're passing to the model are wrong.

Looking at forms.py i see these as possible attributes:

email = StringField(validators=[DataRequired(), Email()])
password = PasswordField(validators=[DataRequired(), Length(min=8)])

Looking at model.py (which may...possibly...be more significant in terms of

' attributes you're passing to the model')

I see these lines:

email = CharField(unique=True)
password = CharField(max_length=100)
join_date = DateTimeField(default=datetime.datetime.now)
bio = CharField(default='')

I try 'mirroring' these fields (and dropping the username) in lunch.py using

def register():
    form = forms.SignUpForm()
    flash("Thanks for registering!", "success")
    if form.validate_on_submit():
      models.User.new(            
            email=form.email.data,
            password=form.password.data,
            join_date=form.username.data,
            bio=form.username.data,
      )
      return redirect(url_for('index'))
    return render_template('register.html', form=form)

But I got the same 'Bummer! Didn't get a 200 at '/register'.'

So clearly I'm still missing something..


Edit 1:

Kept playing around and eventually I managed to get it to pass just using the email and password lines under 'models.User.new( '

So it looks like the attributes in the forms.py, (not the model.py), are the ones that need to be used in lunch.py..

..but I had to work through a bunch of "Task 1 is no longer passing" errors, so don't ask me what the final passing code looked like...

As long as I'm passed that challenge, I'm just going to leave it in the rear view mirror and forgetaboutit!

I still need to pass task 4 of 4 for the form with validators challenge in 'Takin' Names section, so I'll move on to that..

Link:

http://teamtreehouse.com/library/build-a-social-network-with-flask/takin-names/form-with-validators

from flask_wtf import Form
from wtforms import StringField, PasswordField
from wtforms.validators import (DataRequired, Regexp, ValidationError,
                                Email, Length, EqualTo)

class SignUpForm(Form):
    email = StringField(
        'Email',
        validators=[
            DataRequired(),
            Email()
        ])
    password = PasswordField(
        'Password',
        validators=[
            DataRequired(),
            Length(min=8)
        ]

Edit (later) : stupid stupid me...just forgot an extra parenthesis at the end..nevermind!

Gavin Ralston
Gavin Ralston
28,770 Points

I think the key was even after removing the User information from the register route function, you had a form that submitted this:

if form.validate_on_submit():
      models.User.new(            
            email=form.email.data,
            password=form.password.data,
            join_date=form.username.data,
            bio=form.username.data,
      )

I'm not sure there was a join_date or a bio attribute for the users in the lunch.py program from the exercises, so in that case you were still submitting information that isn't needed in the User class's create method:

    @classmethod
    def new(cls, email, password):
        cls.create(
            email=email,
            password=generate_password_hash(password)
        )
        # User.new just needs an email and a password

Also it's not in the form itself:

class SignUpForm(Form):
    email = StringField(validators=[DataRequired(), Email()])
    password = PasswordField(validators=[DataRequired(), Length(min=8)])
    # your form just has an email and a password

So maybe when you were validating the submission, it was failing because it couldn't see the bio and join_date in the POST data, and even if you fixed that, you also had the User's new method complaining that there was no need for the extra arguments.

I think it would be so helpful if when you passed a code challenge it was retained so you could go back and look at it later.

Hopefully it all works out and some epiphany will be reached after a good rest, or fiddling with Flask some more, because understanding the MVC structure of frameworks like Flask and Django seems...very much central to the learning process here. :)

@app.route('/register', methods=('GET', 'POST'))
def register(email, password):
        cls.create(
            email=email,
            password=generate_password_hash(password)
        )

hi james

I have been working on task 3 of 3 for over 30 minutes

is this what you meant by "I managed to get it to pass just using the email and password lines under

'models.User.new( '"?

I have the same problem. When i am learning by myself i always have pdb and werkzeug debugger so if something is broke i am able to debug it by mysel or give traceroute to some people that know more about python.