0

I've had a look at a very similar issue, but the solution isn't working for me, and I was wondering if I could get some guidance.

This is my application structure:

mosiman/
  __init__.py
  blog/
    __init__.py
    blogconfig.py
    blog.py
    static/
      ...
    templates/
      ...

I really wanted a way to build separate apps but manage them from one application instance so I wouldn't have to touch the WSGI layer, and blueprints seemed like the best way.

Here's what I think the relevant files are:

# mosiman/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import blog.blog as blog
...
...
db = SQLAlchemy()
...
...
def create_app():
    app = Flask(__name__)
    db_path = os.path.join(os.path.dirname(__file__), 'mosiman.db')
    app.config["SQLALCHEMY_DATABASE_URI"] = 'sqlite:///{}'.format(db_path)
    app.config["SQLALCHEMY_BINDS"] = {'blog': os.path.join(os.path.dirname(__file__), 'blog/blog.db')
    db.init_app(app)
    app.register_blueprint(blog.blog, url_prefix='/blog')
    return app
if __name__ == '__main__':
    app = create_app()
    app.run(debug=True)

I also have in my mosiman/blog/blog.py file:

#mosiman/blog/blog.py
<<< all of the usual flask imports and SQLAlchemy, etc >>>
from .__init__ import db
blog = Blueprint('blog', __name__)
...
...
class Entry(db.Model):
    __bind_key__ = "blog"
    id = db.Column(db.Integer, primary_key = True)
    title = db.Column(db.String(150))
    ...
    ...

Here is my problem: I actually don't have a "default" database, so I have no classes for it. But I do want to initialize my blog database with the class Entry.

The default procedure for initializing the database seems to be to pop into the python REPL, import the database, and run db.create_all()

Well, I can't just import db and run db.create_all() because db hasn't been attached to an app yet (done in create_app()) This is how I proceed:

# pop open a REPL at mosiman/
>>> from __init__ import db
>>> from __init__ import create_app
>>> app = create_app()
>>> db.init_app(app)
>>> from blog.blog import Entry
>>> db.init_app(app)
# At this point, db still isn't attached to an engine?
>>> db
<SQLAlchemy engine=None>
>>> with app.app_context():
...     db.create_all()
...
>>>

Now, when I go to mosiman/blog/ I find that blog.db has been created, but when I check the schema and tables in SQLite3 nothing turns up.

1 solved their problem by changing from __init__ import db to from mosiman import db

If I try to do that inside mosiman/:

>>> from mosiman import db
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'mosiman'

even though I've got an __init__.py in there.

If I run it from ../ (the directory above mosiman):

>>> from mosiman import db
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/users/d49chan/mosiman/__init__.py", line 3, in <module>
    import blog.blog as blog
ModuleNotFoundError: No module named 'blog'

I'm not sure how to proceed. Maybe it's because I need sleep, but I've been trying to understand why nothing works for the past many hours. If you could point me in the right direction or possibly clear up some of my misunderstandings I'd be very grateful.

Dillon Chan
  • 145
  • 1
  • 2
  • 9

1 Answers1

0

1) You don't namely import __init__.py. You should import it with the name of the directory (package) it's in.

2) You shouldn't import like this: import blog.blog. Instead you should: from blog import blog.

3) Be sure you have an __init__.py file in every directory so that the python importer can treat it as a package (directory) it can import from.

4) There's a difference between relative importing and absolute importing.

Relative importing:

# l3_module.py in l3_package
from ..l1_package import l1_module

This imports a module located two packages (directories) up in relation to the module importing it.

Now assuming l3_package is in an l2_package which is in an l1_module, You can also import it as such

Absolute importing:

# l3_moudle.py in l3_package
from l1_package import l1_module

This will also work, but then it sometimes messes stuff up, depending on your env. Here's an excellent answer that can clear some stuff up for you: Relative imports for the billionth time.

Hope that helped :)

Charming Robot
  • 2,460
  • 2
  • 17
  • 34
  • I have `__init__.py`s in each directory. Why is it that when I run the interpreter inside my top-level directory (`mosiman`) the interpreter doesn't recognize `mosiman` as a module, but when I run it from a directory above, it does? – Dillon Chan Sep 30 '18 at 14:20
  • Because how Python handles importing is that it follows some procedures to search for your requested import. Not sure which comes first, but one of those steps involves searching the `os.cwd()` (current working dir) and NOT upper level directories. So, in your case, you're telling python to import a module it cannot find in any of its default paths. That's why it's failing. – Charming Robot Sep 30 '18 at 17:29
  • Yeah, but I'm running the interpreter where my __init__.py file is. I.e., if we have `/app/__init__.py` and I run the interpreter when I am inside `/app/`, python can't find the `app` module – Dillon Chan Oct 01 '18 at 04:59