0

I have a Python/Flask app that uses MongoEngine for the database. I have defined my models, and everything was working until the newest models were added. I believe the problem occurs because both models reference each other and it's causing a recursive import loop. I'm not sure what to do to solve it though. This is going to be a large project with lots of models referencing each other. This particular instance is because users are in practices, and practices have users, so it's a many to many relationship.

User Model

from utilities.common import utc_now_ts as now
from mongoengine import *
from models.practice import Practice

class User(Document):
    name = StringField()
    created = IntField(db_field="cr", default=now)
    practices = ListField(ReferenceField(Practice))

And the practice model

from utilities.common import utc_now_ts as now
from mongoengine import *
from models import user

class Practice(Document):
    name = StringField()
    created = IntField(db_field="cr", default=now)
    users = ListField(ReferenceField(user.User))
    admins = ListField(ReferenceField(user.User))

The error I get is ImportError: cannot import name 'Practice'

I have two other models that are running into the same issue. The models worked fine until I added in the imports to the other model.

Jhorra
  • 6,233
  • 21
  • 69
  • 123
  • Is there a reason that they are recursively referenced? The best way to solve this issue is most likely going to be a model refactor to remove one of the dependencies. – Robert Wisner Dec 20 '16 at 19:51
  • Can you show me how to change it? I need to have a list of users for each model, and I need to have a list of groups for each user. This was the method people recommended when I searched on the topic. – Jhorra Dec 20 '16 at 19:54

2 Answers2

2

The short answer is that you can't have circular references. The compiler doesn't trust that you will properly "bottom out" on resolving references, and it's not going to iterate through the graph to find out.

One way to fix this is to use a master class that imports the various classes; your worker classes then import their needs from the master class.

Prune
  • 76,765
  • 14
  • 60
  • 81
  • Assuming these were my only two classes, could you give me an example of what the master class would look like. – Jhorra Dec 20 '16 at 20:33
  • 1
    Try the discussion [here] (http://stackoverflow.com/questions/1556387/circular-import-dependency-in-python) – Prune Dec 20 '16 at 21:54
2

I am by no means an expert on MongoEngine, but it looks like you can reference a model by string as opposed to by class. In that case you can change your Practice model to look like this.

from utilities.common import utc_now_ts as now
from mongoengine import *


class Practice(Document):
    name = StringField()
    created = IntField(db_field="cr", default=now)
    users = ListField(ReferenceField('User'))
    admins = ListField(ReferenceField('User'))

I hope this helps.

Robert Wisner
  • 155
  • 1
  • 5