3

i'm using sqlalchemy + alembic + Flask and i can't map circular classes.

apps/users/models.py:

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    email = Column(String)
    password = Column(String)
    session = relationship("Session", back_populates='user', cascade='all,delete', lazy='dynamic')

    notes = relationship('Note2User', back_populates='user', cascade='all,delete', lazy='dynamic')

apps/notes/models.py:

class Note2User(Base):
    __tablename__ = 'notes_users_m2m'

    id = Column(Integer, primary_key=True)

    user_id = Column(Integer, ForeignKey('users.id', ondelete='CASCADE'), nullable=False)
    user = relationship('User', back_populates='notes')
    note_id = Column(Integer, ForeignKey('notes.id', ondelete='CASCADE'), nullable=False)
    note = relationship('Note', back_populates='users')

Table Note2User made for m2m relationship User <-> Notes, but when i start app and done some request, gets error:

InvalidRequestError: When initializing mapper Mapper|User|users, expression 'Note2User' failed to locate a name ("name 'Note2User' is not defined"). If this is a class name, consider adding this relationship() to the class after both dependent classes have been defined.

Initializing db in db/init.py: (dunder name)

from sqlalchemy import create_engine, MetaData
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session

engine = create_engine('postgresql+psycopg2://server:12345@localhost:5432/test')

Base = declarative_base()

meta = MetaData()
meta.reflect(bind=engine)

db_session = Session(bind=engine)

2 Answers2

4

Add an import for Note2User class in apps/users/models.py file so this model gets defined first before initializing that relatioship in User class which refrences it. like this

# file: apps/users/models.py
from ..notes.models import Note2User
Zohaib Ijaz
  • 21,926
  • 7
  • 38
  • 60
  • 1
    this worked, but i am still guessing should not framework take care of all registered classes, names and relations? – silentsudo Aug 17 '19 at 14:04
2

You need to import the user.models module into the notes.model module and vice versa. It would look something like this:

# file app/users/models.py
import app.notes.models as notes
# use it like this
notes.Notes2User()


# file app/notes/models.py
import app.users.models as users
users.User()

The advantage to this is that you will avoid circular dependency problems as your program inevitably grows. I had so many problems with circular dependencies when I was creating an app with your same stack. The only solution was to ditch the

from . import Foo

and only use

import bar.foo as foo

It is considered best practice to use the import syntax for this reason. Reference.

Kyle Stuart
  • 111
  • 5