Forums

Trouble getting user logins to work with Flask

I've been working through chapters 3 and 4 of the Flask mega-tutorial (https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-iv-database). I'm trying to set up user logins on my flask webpage that I have hosted at pythonanywhere. I'm able to register an account successfully (I can see the record added to my database), however, when I try to login, Flask is unable to find the record when searching for the username and it returns None. I'm not sure why this is happening. Complicating things a bit is that I'm using a MySQL database rather than a SQLLite database that the tutorial uses.

config.py:

import os
basedir = os.path.abspath(os.path.dirname(__file__))

class Config(object):
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'something'
    SQLALCHEMY_DATABASE_URI = 'mysql+mysqlconnector://username:password@jplank.mysql.pythonanywhere-services.com/jplank$default'
    SQLALCHEMY_TRACK_MODIFICATIONS = False

flask_app.py:

from config import Config
from flask_sqlalchemy import SQLAlchemy
from werkzeug.urls import url_parse
from flask import Flask, render_template, flash, redirect, url_for, request
from pandas import DateOffset, DataFrame, date_range, to_datetime
from flask_login import current_user, login_user, logout_user, login_required, LoginManager
import MySQLdb
from flask_bootstrap import Bootstrap
from numpy import nan
from dateutil.relativedelta import relativedelta
import datetime
import math
from yearfrac import CalcYearFrac
import decimal
from sqlalchemy import create_engine

app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
login = LoginManager(app)
login.login_view = 'login'
Bootstrap(app)

from forms import NameForm, LoginForm, RegistrationForm
import routes, models

@app.route('/table', methods=('GET', 'POST'))
@login_required
def calculatetable():
[...]

models.py:

from flask_app import db, login
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin

class User(UserMixin, db.Model):
    __tablename__ = "user"

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), index=True, unique=True)
    email = db.Column(db.String(120), index=True, unique=True)
    password_hash = db.Column(db.String(128))

    def __repr__(self):
        return '<User {}>'.format(self.username)

    def set_password(self, password):
        self.password_hash = generate_password_hash(password)

    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

@login.user_loader
def load_user(id):
    return User.query.get(int(id))

routes.py:

from flask import render_template, flash, redirect, url_for, request
from flask_login import login_user, logout_user, current_user
from werkzeug.urls import url_parse
from flask_app import app, db
from forms import LoginForm, RegistrationForm
from models import User
from config import Config

@app.route('/logout')
def logout():
    logout_user()
    return redirect(url_for('index'))

@app.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    form = LoginForm()
    if form.validate_on_submit():
        user = 
User.query.filter_by(username=form.username.data).first()
        if user is None:
            flash('user is none')
            flash(form.username.data)
            return redirect(url_for('login'))
        elif not user.check_password(form.password.data):
            flash('not hash match')
            return redirect(url_for('login'))
        login_user(user, remember=form.remember_me.data)
        next_page = request.args.get('next')
        if not next_page or url_parse(next_page).netloc != '':
            next_page = url_for('calculatetable')
        return redirect(next_page)
    return render_template('login.html', title='Sign In', form=form)

@app.route('/register', methods=['GET', 'POST'])
def register():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    form = RegistrationForm()
    if form.validate_on_submit():
        user = User(username=form.username.data, email=form.email.data)
        user.set_password(form.password.data)
        db.session.add(user)
        db.session.commit()
        flash('Congratulations, you are now a registered user!')
        return redirect(url_for('login'))
    return render_template('register.html', title='Register', form=form)

If you're getting a None when you're querying your database for a record, check that the record you're looking for is actually in the database.

I have looked into that. When I open the MySQL console and manually query the database, I can see the record that should be returned.

I believe that SQLALchemy has a way of showing the SQL that is being generated. Try using that on the query that is doing the user lookup and then you may see why it's not working or you can try it in a MySQL console.

Thank you! That led me to figuring out that I had set up the table incorrectly. Deleting and re-creating the table solved my issue. Apparently I forgot to identify certain columns as index.