Ross
Ross

Reputation: 46987

SQLAlchemy cannot find a class name

Simplified, I have the following class structure (in a single file):

Base = declarative_base()

class Item(Base):
    __tablename__ = 'item'
    id = Column(BigInteger, primary_key=True)
    # ... skip other attrs ...

 class Auction(Base):
     __tablename__ = 'auction'
     id = Column(BigInteger, primary_key=True)
     # ... skipped ...
     item_id = Column('item', BigInteger, ForeignKey('item.id'))

     item = relationship('Item', backref='auctions')

I get the following error from this:

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

I'm not sure how Python cannot find the Item class, as even when passing the class, rather than the name as a string, I get the same error. I've been struggling to find examples of how to do simple relationships with SQLAlchemy so if there's something fairly obvious wrong here I apologise.

Upvotes: 79

Views: 78519

Answers (11)

Abinash
Abinash

Reputation: 717

I had the same issue, i solved them by using the same Base for every models.

from sqlalchemy.orm import declarative_base
Base = declarative_base()

Imported this Base and used in all the models.

Upvotes: 2

Deepam Gupta
Deepam Gupta

Reputation: 2692

Case with me

Two models defined in separate files, one is Parent and the other is Child, related with a Foreign Key. When trying to use Child object in celery, it gave

sqlalchemy.exc.InvalidRequestError: When initializing mapper Mapper|Child|child, expression 'Parent' failed to locate a name ("name 'Parent' is not defined"). If this is a class name, consider adding this relationship() to the <class 'app.models.child'>

parent.py

from app.models import *


class Parent(Base):
    __tablename__ = 'parent'

    id = Column(BigInteger, primary_key=True, autoincrement=True)
    name = Column(String(60), nullable=False, unique=True)
    number = Column(String(45), nullable=False)

child.py

from app.models import *


class Child(Base):
    __tablename__ = 'child'

    id = Column(BigInteger, primary_key=True, autoincrement=True)
    parent_id = Column(ForeignKey('parent.id'), nullable=False)
    name = Column(String(60), nullable=False)

    parent = relationship('Parent')

Solution

Add an import statement for Parent in beginning of child.py

child.py (modified)

from app.models import *
from app.models.parent import Parent  # import Parent in child.py


class Child(Base):
    __tablename__ = 'child'

    id = Column(BigInteger, primary_key=True, autoincrement=True)
    parent_id = Column(ForeignKey('parent.id'), nullable=False)
    name = Column(String(60), nullable=False)

    parent = relationship('Parent')

Why this worked

The order in which models get loaded is not fixed in SQLAlchemy.
So, in my case, Child was being loaded before Parent. Hence, SQLAlchemy can't find what is Parent. So, we just imported Parent before Child gets loaded.

Upvotes: 14

satyam_naithani
satyam_naithani

Reputation: 69

Use back_populates for relationship mapping in both models. Also keep in mind to import both the models in the models/__init__.py

Base = declarative_base()

class Item(Base):
    __tablename__ = 'item'
    id = Column(BigInteger, primary_key=True)
    # ... skip other attrs ...
    auctions = relationship('Auction', back_populates='item')

 class Auction(Base):
     __tablename__ = 'auction'
     id = Column(BigInteger, primary_key=True)
     # ... skipped ...
     item_id = Column('item', BigInteger, ForeignKey('item.id'))

     item = relationship('Item', back_populates='auctions')

Upvotes: 0

Nathan
Nathan

Reputation: 471

I had yet another solution, but this helped clue me in. I was trying to implement versioning, from https://docs.sqlalchemy.org/en/14/orm/examples.html#versioning-objects using the "history_mapper" class.

I got this same error. All I had to do to fix it was change the order in which my models were imported.

Upvotes: 0

Laurens
Laurens

Reputation: 341

I had a different error, but the answers in here helped me fix it.

The error I received:

sqlalchemy.exc.InvalidRequestError: When initializing mapper mapped class Parent->parents, expression 'Child' failed to locate a name ('Child'). If this is a class name, consider adding this relationship() to the <class 'parent.Parent'> class after both dependent classes have been defined.

My set-up is similar toDeepam's answer.

Briefly what I do different:

  • I have multiple separate .py files for each db.Model.
  • I use a construct/fill database .py file that pre-fills db.Model objects in either Multi-threading or single threading way

What caused the error:

  • Only in multi-threaded set up the error occured
  • This construct/fill .py script did import Parent, but not Child.

What fixed it:

  • Adding an import to Child fixed it.

Upvotes: 1

Dublado
Dublado

Reputation: 21

My Solution

One models file, or even further, if you need.

models.py

from sqlalchemy import Boolean, BigInteger, Column, DateTime, Float, ForeignKey, BigInteger, Integer, String
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

from .parent import Parent 
from .child import Child 

parent.py

from sqlalchemy import Boolean, BigInteger, Column, DateTime, Float, ForeignKey, BigInteger, Integer, String
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base

#Base = declarative_base()

class Parent(Base):
    __tablename__ = 'parent'

    id = Column(BigInteger, primary_key=True, autoincrement=True)
    name = Column(String(60), nullable=False, unique=True)
    number = Column(String(45), nullable=False)

child.py

from sqlalchemy import Boolean, BigInteger, Column, DateTime, Float, ForeignKey, BigInteger, Integer, String
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Child(Base):
    __tablename__ = 'child'

    id = Column(BigInteger, primary_key=True, autoincrement=True)
    parent_id = Column(ForeignKey('parent.id'), nullable=False)
    name = Column(String(60), nullable=False)

    parent = relationship('Parent')

Why this worked

Same Deepam answer, but with just one models.py file to import another models

Upvotes: 2

Bob Rusovčev
Bob Rusovčev

Reputation: 51

I've solved the same error by inheriting a 'db.Model' instead of 'Base'... but I'm doing the flask

Eg:

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()


class someClass(db.Model):
    someRelation = db.relationship("otherClass")

Upvotes: 5

Christopher Peisert
Christopher Peisert

Reputation: 24124

The SQLAlchemy documentation on Importing all SQLAlchemy Models states in part:

However, due to the behavior of SQLAlchemy's "declarative" configuration mode, all modules which hold active SQLAlchemy models need to be imported before those models can successfully be used. So, if you use model classes with a declarative base, you need to figure out a way to get all your model modules imported to be able to use them in your application.

Once I imported all of the models (and relationships), the error about not finding the class name was resolved.

  • Note: My application does not use Pyramid, but the same principles apply.

Upvotes: 25

mosi_kha
mosi_kha

Reputation: 572

if it's a subpackage class, add Item and Auction class to __init__.py in the subpackage.

Upvotes: 30

Katie Byers
Katie Byers

Reputation: 1010

Also, even though this doesn't apply to the OP, for anyone landing here having gotten the same error, check to make sure that none of your table names have dashes in them.

For example, a table named "movie-genres" which is then used as a secondary in a SQLAlchemy relationship will generate the same error "name 'movie' is not defined", because it will only read as far as the dash. Switching to underscores (instead of dashes) solves the problem.

Upvotes: 5

Ross
Ross

Reputation: 46987

This all turned out to be because of the way I've set SQLAlchemy up in Pyramid. Essentially you need to follow this section to the letter and make sure you use the same declarative_base instance as the base class for each model.

I was also not binding a database engine to my DBSession which doesn't bother you until you try to access table metadata, which happens when you use relationships.

Upvotes: 50

Related Questions