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 Broadcasting Stream Templates

rshap
rshap
12,433 Points

Problems with the "validate_on_submit()" function (I think...)

I'm having problems with the code that I've been writing along with the videos. Every time that I register or submit a new post the page just refreshes (the else of the if form.validate_on_submit() happens). Maybe some of the names of the imported files or the validators has been changed? Please help Kenneth Love...

Chris Jones
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Chris Jones
Java Web Development Techdegree Graduate 23,933 Points

Hi roeespaira,

Could you post a link to your workspace or at least the code that you reference (the form.validate_on_submit method)?

Thanks!

rshap
rshap
12,433 Points
from flask import Flask, g, render_template, flash, redirect, url_for
from flask_bcrypt import check_password_hash
from flask_login import (LoginManager, login_user, logout_user,
                            login_required, current_user)

import forms
import models


DEBUG = True
PORT = 8000
HOST = '127.0.0.1'

app = Flask(__name__)
app.secret_key = 'isbfF74tG75 HbgX-<x9et*b/.hbbuh#-@ib5G'

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.get(models.User.id == userid)
    except models.DoesNotExist:
        return None


@app.before_request
def before_request():
    """Connect to the database before each request.
    """
    g.db = models.DATABASE
    g.db.connect()
    g.user = current_user


@app.after_request
def after_request(response):
    """Close the database connection after each request.
    """
    g.db.close()
    return response


# Doesn't work
@app.route('/register', methods = ('GET', 'POST'))
def register():
    form = forms.RegistarationForm()
    if form.validate_on_submit():
        flash("Registration successful!", "success")
        models.User.create_user(
            username = form.username.data,
            email = form.email.data,
            password = form.password.data
        )
        return redirect(url_for('index'))
    return render_template('register.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:
            flash("The email and password you've entered don't match." , "error")
        else:
            if check_password_hash(user.password, form.password.data):
                login_user(user)
                flash("You've been logged in successfully.", "success")
                return redirect(url_for('index'))
            else:
                flash("The email and password you've entered don't match." , "error")
    return render_template('login.html', form = form)


@app.route('/logout')
@login_required
def logout():
    logout_user()
    flash("You've been logged out.", "success")
    return redirect(url_for('index'))


# Doesn't work
@app.route('/new_post', methods = ('GET', 'POST'))
@login_required
def post():
    post = forms.PostForm()
    if post.validate_on_submit():
        models.Post.create(
            user = g.user._get_current_object(),
            content = post.content.data.strip()
        )
        flash("Message posted successfully!", "success")
        return redirect(url_for('index'))
    return render_template('post.html', form = post)


@app.route('/stream')
@app.route('/stream/<username>')
def stream(username = None):
    template = 'stream.html'
    if username and username != current_user.username:
        user = models.User.select().where(models.User.username ** username).get()
        stream = user.posts.limit(100)
    else:
        user = current_user
        stream = current_user.get_stream().limit(100)
    if username:
        template = 'user_stream.html'
    return render_template(template, stream = stream, user = user)


@app.route('/')
def index():
    stream = models.Post.select().limit(100)
    return render_template('stream.html', stream = stream)


if __name__ == '__main__':
    models.initialize()
    try:
        models.User.create_user(
            username = 'superuser',
            email = 'superuser@gmail.com',
            password = 'password',
            is_admin = True
        )
    except ValueError:
        pass
    app.run(debug = DEBUG, port = PORT, host = HOST)

I pasted here my code. Sorry and thank you :)

Chris Jones
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Chris Jones
Java Web Development Techdegree Graduate 23,933 Points

Thanks for sharing the code. This helps, but I have questions that seeing the rest of your workspace will help answer. Can you create a snapshot of your workspace by following the instructions in this post:

https://teamtreehouse.com/community/workspace-snapshots

Thank you!

5 Answers

Chris Jones
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Chris Jones
Java Web Development Techdegree Graduate 23,933 Points

I'd like to see your RegistrationForm class and PostForm class. The Flask documentation for Form classes shows that these types of classes take a Form parameter. However, you're not passing anything to your RegistrationForm and PostForm constructors in the code you shared. So, essentially you're creating a blank form object, which may not pass the validate_on_submit() method, which wouldn't post your form data and would just redirect you back to the login.html or post.html pages.

But having a snapshot of your workspace (see my last comment on how to make a snapshot) will help determine if I'm correct in my thinking.

rshap
rshap
12,433 Points

https://w.trhou.se/q9brwqzdiw A few of the package names I've changed from the videos because the python program on my pc told me to... And thanks again :)

Chris Jones
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Chris Jones
Java Web Development Techdegree Graduate 23,933 Points

Thanks!

Yeah, your RegistrationForm class takes a FlaskForm parameter, but you're not passing anything to it in app.py. The Flask documentation shows that you need to pass it request.form. If you try passing request.form to the constructor, does that solve your issue?

The same thing is happening with the PostForm class.

class RegistarationForm(FlaskForm): #class constructor requires a FlaskForm parameter.
    username = StringField(
        'Username',
        validators = [
            DataRequired(),
            Regexp(
                r'^[a-zA-Z0-9]+$',
                message = "The username should be one word with letters,"
                + " numbers, and underscores only."
            ),
            name_exists
        ]
    )
    email = StringField(
        'E-mail',
        validators = [
            DataRequired(),
            Email(),
            email_exists
        ]
    )
    password = PasswordField(
        'Password',
        validators = [
            DataRequired(),
            Length(min = 5, message = 'Your password must be at least 5 characters long.'),
        ]
    )
    password2 = PasswordField(
        'Confirm Password',
        validators = [
            DataRequired(),
            EqualTo('password', message = 'The two passwords must match.')
        ]
    )

class PostForm(FlaskForm):
    content = TextAreaField("Type your post into here", validators = [DataRequired()])
rshap
rshap
12,433 Points

I'm sorry, but I'm confused, where you placed your comment, isn't that the place for inheritance?

Chris Jones
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Chris Jones
Java Web Development Techdegree Graduate 23,933 Points

Oh no, I'm sorry, total lapse on my part. Thanks for pointing out my mistake! Admittedly, I don't spend a lot of time with Python :)!

Looks like the problem isn't your form classes. But, when I look at the Flask documentation I see that you're supposed to pass the request's form to the RegistrationForm (see below):

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm(request.form) # The request's form is passed to RegistrationForm.
    if request.method == 'POST' and form.validate():
        user = User(form.username.data, form.email.data,
                    form.password.data)
        db_session.add(user)
        flash('Thanks for registering')
        return redirect(url_for('login'))
    return render_template('register.html', form=form)

However, you're not passing the request's form (see below):

# Doesn't work
@app.route('/register', methods = ('GET', 'POST'))
def register():
    form = forms.RegistarationForm() # request's form is NOT passed to RegistrationForm.
    if form.validate_on_submit():
        flash("Registration successful!", "success")
        models.User.create_user(
            username = form.username.data,
            email = form.email.data,
            password = form.password.data
        )
        return redirect(url_for('index'))
    return render_template('register.html', form = form)

I also see this in the link to the documentation:

Things to remember:

1) create the form from the request form value if the data is submitted via the HTTP POST method and args if the data is submitted as GET.

2) to validate the data, call the validate() method, which will return True if the data validates, False otherwise.

3) to access individual values from the form, access form.<NAME>.data.

rshap
rshap
12,433 Points

I'm sorry, but the registration does work, but just the flash() function doesn't. Although the post() function still doesn't work at all (the verify_on_submit() if) and the flash() function in general.

rshap
rshap
12,433 Points

Yes, a new user is created and then I can use it for anything but post. Plus the flash() function doesn't work at all (but doesn't give out any error either)...