-1

I set a database instance shared by many models:

Database.py:

from flask_sqlalchemy import SQLAlchemy
from models.shared import load_db

def init_db(app):
    db = SQLAlchemy(app)
    load_db(db)
    from models.user import User
    from models.another_model import AnotherModel
    from ...

init_db is called from create_app in my main server.py file.

Shared.py:

db = None
def load_db(_db):
    db = _db
    print(db)

User.py:

from .shared import db
print("User model defined.")
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(15), unique=True, nullable=False)
    hash = db.Column(db.String(32), nullable=False)
    email = db.Column(db.String(100), unique=True, nullable=False)

    def __repr__(self):
        return '<User %r>' % self.username

When init_db is called from the create_app method in my main file I get:

AttributeError: 'NoneType' object has no attribute 'Model'

Why am I getting this error? When importing the model modules from inside init_db shouldn't their code run after I call load_db? Looking at the order of the print statements db is clearly set before any model uses it:

<SQLAlchemy engine=mysql://root:***@localhost/db_name?charset=utf8>
User model defined.
ᴀʀᴍᴀɴ
  • 4,443
  • 8
  • 37
  • 57
Tagor
  • 937
  • 10
  • 30

1 Answers1

2

In

def load_db(_db):
    db = _db
    print(db)

You're actually declaring a variable db local to the function load_db. To actually refer to global db variable try global db expression:

def load_db(_db):
    global db
    db = _db
    print(db)

I find this code pretty flaky, though, I would think about using singletones or some other approach.

Consider a case where you imported db before it has been initialized. Like:

from .shared import db
save_for_later_use(db)

Even if you replace the db in shared module, shared.db will point to the initialized value, while you'll have uninitialized value already pointed to by variable you stored somewhere in save_for_later_use. In other words, you've replated what shared.db points to, but whichever code tried to remember shared.db before the initialization will still hold a pointer to None.

Andrew_Lvov
  • 4,621
  • 2
  • 25
  • 31