mysqlflaskmysql-python

'NoneType' object has no attribute 'cursor'


I have created a very simple web app using Flask and I have a MySQL database connected. FYI, I am using bash on windows.

The below function registers a person into the Mysql Database and it works as expected. The cursor object is defined and data are saved into MySQL.

@app.route('/register', methods=['GET','POST'])
def register():
    form = RegisterForm(request.form)
    if request.method == 'POST' and form.validate():
        name = form.name.data
        email = form.email.data
        username = form.username.data
        password = hash.encrypt(str(form.password.data))

        # Create cursor
        cur = mysql.connection.cursor()
        cur.execute("INSERT INTO users(name, email, username, password) VALUES(%s, %s, %s, %s)",
        [name, email, username, password])

        # commit to db
        mysql.connection.commit()

        # close connection
        cur.close()

        flash('You are now registered and can log in', 'success')

        return redirect(url_for('login'))

    return render_template('register.html', form=form)

The problem starts when I want to load data from mysql:

def data():
    cur = mysql.connection.cursor()
    cur.execute("SELECT * FROM users")
    mysql.connection.commit()
    cur.close()

data()

I get the error:

File "app.py", line 23, in data cur = mysql.connection.cursor() AttributeError: 'NoneType' object has no attribute 'cursor'

As pointed out by @Martijn Pieters, this means that I could not connect to the mysql database. The question is, why does flask connect without a problem in the first function and has issues with the second function?

Below are my imports for replication:

from flask import Flask, render_template, flash, request, redirect, url_for, session, logging, url_for
from data import Articles
from flask_mysqldb import MySQL
from wtforms import Form, StringField, TextAreaField, PasswordField, validators
from passlib.hash import sha256_crypt

app = Flask(__name__)

#init MYSQL
mysql=MySQL(app)

Solution

  • The error occurs because mysql.connection is None. It doesn't matter here what type of object mysql is.

    The Flask-MySQL documentation for MySQL.connection tells you when that attribute is going to be None:

    Attempts to connect to the MySQL server.

    Returns: Bound MySQL connection object if successful or None if unsuccessful.

    So the attempt to connect to the server could have failed. The extension will open a connection to MySQL once per request; it failed to connect on a separate request from the one that succeeded.

    Looking at the source code for the extension I see that it'll also return None when there is no app context (at which point _app_ctx_stack.top is None). You can't use this function outside of a request.

    If you do need this outside of a request, you need to manually create an app context first:

    with app.app_context():
        cur = mysql.connection.cursor()