Python Flask Login login_required redirecting
Question: I am working on a Flask app and using Flask-Login for authentication.
Everything is set up and running. However when the user logins in and attempts
to visit a page that requires login, they are redirected to the login page.

When watching the console, I get a 200 for the GET login page, a 200 for the
POST on the login, a 302 from the login page to the home page, and then
another 302 from the homepage back to login.

See code below.

    
    
    from flask import (Flask, render_template, g, flash, redirect, url_for,
                        request)
    from flask_bcrypt import check_password_hash
    from flask_login import (LoginManager, UserMixin, login_required, login_user,
                            logout_user, current_user)
    
    import models
    import forms
    
    application = Flask(__name__)
    application.secret_key = "xxx-xxx-xxx-xxx"
    login_manager = LoginManager()
    login_manager.init_app(application)
    login_manager.login_view = "login"
    
    @application.before_request
    def before_request():
        g.db = models.DATABASE
        g.db.connect()
        g.user = current_user
    
    @application.after_request
    def after_request(response):
        g.db.close()
        return response
    
    @login_manager.user_loader
    def load_user(email):
        try:
            return models.User.select().where(
                                    models.User.email == email).get()
        except models.DoesNotExist:
            return None
    
    @application.route("/register", methods=['GET', 'POST'])
    def register():
        form = forms.RegisterForm()
        if form.validate_on_submit():
            flash("Yay! You registered!", "success")
            models.User.create_user(
                email = form.email.data,
                password = form.password.data
            )
            return redirect(url_for('home'))
        return render_template('register.html',form=form)
    
    @application.route("/login", methods=['GET', 'POST'])
    def login():
        form = forms.LoginForm()
        if form.validate_on_submit():
            next = request.args.get('next')
            try:
                user = models.User.get(models.User.email == form.email.data)
            except models.DoesNotExist:
                flash("Your email or password doesn't match!", "error")
            else:
                if check_password_hash(user.password, form.password.data):
                    login_user(user, remember=True)
                    flash("Welcome back!", "success")
                    return redirect(next or url_for("home"))
                else:
                    flash("Your email or password doesn't match!", "error")
        return render_template("login.html", form=form)
    
    @application.route("/logout")
    @login_required
    def logout():
        logout_user()
        flash("You've been logged out!", "success")
        return redirect(url_for("home"))
    
    @application.route("/")
    @login_required
    def home():
        return render_template("home.html")
    
    if __name__ == "__main__":
        models.initialize()
        application.run(host='0.0.0.0')
    

Here is the model:

    
    
    import datetime
    
    from flask_login import UserMixin
    from flask_bcrypt import generate_password_hash, check_password_hash
    from peewee import *
    
    DATABASE = MySQLDatabase("fakedatabasename", host="fakehostname", user="fakeusername", password="fakepassword")
    
    
    class BaseModel(Model):
        class Meta:
            database = DATABASE
    
    
    class Preachers(BaseModel):
        preacher_id = PrimaryKeyField()
        preacher_first_name = CharField(max_length=27)
        preacher_last_name = CharField(max_length=27)
        preacher_email = CharField()
    
    
    class Sermons(BaseModel):
        sermon_id = PrimaryKeyField()
        sermon_title = CharField(max_length=27)
        sermon_description = CharField(max_length=140)
        sermon_date = DateTimeField(default=datetime.datetime.now())
        sermon_preacher_id = IntegerField()
        sermon_video_uri = CharField(max_length=255)
    
    
    class User(UserMixin,BaseModel):
        user_id = PrimaryKeyField()
        email = CharField(index=True, unique=True)
        password = CharField()
        date_created = DateTimeField(default=datetime.datetime.now())
    
        @classmethod
        def create_user(cls, email, password):
            try:
                cls.create(
                    email = email,
                    password = generate_password_hash(password)
                )
            except IntegrityError:
                raise ValueError("User already exists")
    
    
    def initialize():
        DATABASE.connect()
        DATABASE.create_tables([Preachers, Sermons, User], safe=True)
        DATABASE.close()
    


Answer: So it turns out that when working with Peewee and Flask-Login, you need to let
Peewee supply its default primary key for the User model instead of using a
custom one. Removing `user_id = PrimaryKeyField()`, dropping the table, and
restarting fixed it.

