Flask with models split into multiple files, how to prevent circular imports?

Viewed 422

I'm having an issue with circular imports, and I'm not sure how to restructure my code to overcome it.

Say I have the structure

├── app
│   ├──__init__.py
│   ├── models_one.py
│   ├── models_two.py

With models_one.py being the following:

from . import db
from .models_two import Post

class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, index=True)
    posts = db.relationship("Post")

    def get_user_posts_with_content(self, passed_content):
        return Post.query.filter(Post.user_id==self.id, Post.content==passed_content).all()

And models_two.py being the following:

from . import db
from .models_one import User

class Post(db.Model):
    __tablename__ = 'posts'
    id = db.Column(db.Integer, primary_key=True)
    content = db.Column(db.String(64))
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)

    def get_user(self):
        return User.query.filter(User.id == self.user_id).first()

This creates a circular import, is there a way to do this without having both classes in the same file? If I had both in a models.py this would work, but for a larger project with 30 models I need a better way to segment them all.

I know that you can get all "posts" in this example by calling User.posts, but in the User model you can see how I use a passed variable as part of the query, my project uses quite a bit of this sort of thing.

I'm also aware that it's because within both classes I have a function that calls a query on the other object, but this simplifies some of the template rendering rather than having to load the data within the view first (unless there's something I'm missing with web development, which is VERY possible).

Thanks for any advice you can give, and sorry if this is a simple question, I've read through the O'Reilly book on Flask Web Development and tackled some simpler projects, but I don't understand this well enough even with a day of googling.

1 Answers

I found this artical. Maybe this helps you. But what the page basically says is, to merge all into one file, so I guess there is no way to do this how you want to do it. But maybe you can delete the methods from the class and insert them into a third module. So basically:

modules_one:

from . import db

class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, index=True)
    posts = db.relationship("Post")

modules_two:

from . import db

class Post(db.Model):
    __tablename__ = 'posts'
    id = db.Column(db.Integer, primary_key=True)
    content = db.Column(db.String(64))
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)

moduels_three:

from .models_one import User
from .models_two import Post

def get_user_posts_with_content(self, passed_content):
    return Post.query.filter(Post.user_id==self.id, Post.content==passed_content).all()

def get_user(self):
    return User.query.filter(User.id == self.user_id).first()
Related