0

I followed the tutorial at https://flask.palletsprojects.com/en/2.0.x/tutorial/factory/ and successfully created the project there. I then tried to apply this to my new project and I'm getting hung up right away. The database schema doesn't seem to get read at any point. At other points in the code I tried to print the tables and got an empty list. Here are the relevant chunks in the code where it should happen.

__init__.py:

import os
from flask import Flask

def create_app(test_config=None):
    app = Flask(__name__, instance_relative_config=True)
    app.config.from_mapping(
        SECRET_KEY='dev',
        DATABASE=os.path.join(app.instance_path, 'projectdb.sqlite')
    )

    if test_config is None:
        app.config.from_pyfile('config.py', silent=True)
    else:
        app.config.from_mapping(test_config)

    try:
        os.makedirs(app.instance_path)
    except OSError:
        pass

    from . import db
    db.init_app(app)

    from . import auth
    app.register_blueprint(auth.bp)
    print("App created")
    return app

db.py:

import sqlite3
import click
from flask import current_app, g
from flask.cli import with_appcontext

def get_db():
    if 'db' not in g:
        g.db = sqlite3.connect(
            current_app.config['DATABASE'],
            detect_types=sqlite3.PARSE_DECLTYPES
        )
        g.db.row_factory = sqlite3.Row

    return g.db

def close_db(e=None):
    db = g.pop('db', None)
    if db is not None:
        db.close()

def init_db():
    db = get_db()

    with current_app.open_resource('schema.sql') as f:
        db.executescript(f.read().decode('utf8'))

@click.command('init-db')
@with_appcontext
def init_db_command():
    init_db()
    click.echo('Initialized the database.')

def init_app(app):
    app.teardown_appcontext(close_db)
    app.cli.add_command(init_db_command)

auth.py:

import functools

from flask import (
    Blueprint, flash, g, redirect, render_template, request, session, url_for
)

from werkzeug.security import check_password_hash, generate_password_hash
from ldmt.db import get_db

bp = Blueprint('auth', __name__, url_prefix='/auth')

@bp.route('/login', methods=('GET', 'POST'))
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        db = get_db()
        error = None
                                              
        user = db.execute(
            'SELECT * FROM user WHERE username = ?', (username,)
        ).fetchone()

        if user is None:
            error = 'invalid username.'
        elif not check_password_hash(user['password'], password):
            error = 'incorrect password.'

        if error is None:
            session.clear()
            session['user_id'] = user['id']
            return redirect(url_for('index'))

        flash(error)
    return render_template('auth/login.html')

@bp.before_app_request
def load_logged_in_user():
    user_id = session.get('user_id')

    if user_id is None:
        g.user = None
    else:
        g.user = get_db().execute(
            'SELECT * FROM user WHERE id = ?', (user_id,)
        ).fetchone()

@bp.route('/logout')
def logout():
    session.clear()
    return redirect(url_for('auth.login'))

def login_required(view):
    @functools.wraps(view)
    def wrapped_view(**kwargs):
        if g.user is None:
            return redirect(url_for('auth.login'))

        return view(**kwargs)

    return wrapped_view

schema.sql:

DROP TABLE IF EXISTS user;

CREATE TABLE user (
       id INTEGER PRIMARY KEY AUTOINCREMENT,
       username TEXT UNIQUE NOT NULL,
       password TEXT NOT NULL
);

The problem happens when I try to login. Nothing has been added to the database so I expect an error that that user is not found, but the error I get is sqlite3.OperationalError: no such table: user

I can also confirm that the .sqlite file is created but empty.

7
  • This is not all the relevant code. Please provide a minimal working example of what problem you are facing. For example where is the code that shows which function gets called when the script runs? What is inside the function get_db(). It's hard to help when there's no code to show the flow of the script, what calls what or anything like that. Also what command are you running to start this script? Commented Jan 16, 2022 at 21:41
  • @TeddyBearSuicide fair point, wasn't sure what else needed to go in, so I may have erred on the side of oversharing now, but that should hopefully cover it. Commented Jan 16, 2022 at 22:04
  • Ok so this is a sqlite error of table not existing. Now you created a flask cli command. Did you run this command before starting the server? Commented Jan 16, 2022 at 22:15
  • No, I started with flask run. I didn't enter any extra commands with the tutorial either. The process is mimicking flask.palletsprojects.com/en/2.0.x/tutorial/database Tracing it, __init__.py is supposed to call db.init_app(): "app.cli.add_command() adds a new command that can be called with the flask command. Import and call this function from the factory. Place the new code at the end of the factory function before returning the app." Commented Jan 16, 2022 at 22:39
  • NOPE. I read it again. Missed a step in the tutorial. I thought it was supposed to just work within the context of the code. Commented Jan 16, 2022 at 22:42

1 Answer 1

1

You created a CLI command for flask here...

@click.command('init-db')
@with_appcontext
def init_db_command():
    init_db()
    click.echo('Initialized the database.')

You will have to run the command in the command line like so...

flask init-db

Sign up to request clarification or add additional context in comments.

3 Comments

Yep, that does it! Thinking ahead, it looks like creating CLI commands like this may also be the way I want to do things like, for instance, adding users or changing passwords?
CLI commands are great for a lot of things. It comes down to security and convenience. For example if you make a website where ppl can register and become a user then CLI for that wouldn't be good. However if special users like you hired someone and they need an admin user then yea CLI it cause its only called occasionally. But I do see CLI being used mostly for database stuff like running backups, migrating changes, building tables and stuff like that were its not very dynamic.
Also CLIs are quicker and easier to create then making a GUI on the frontend to call that specific function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.