0

There are quite a few posts on this error but none of the answers apply to me, as far as I can see my code already conforms to the answers in the other posts.

I import my complete model and it has all classes, columns and relationships defined. In my code on the very first statement I execute I get this error:

InvalidRequestError: When initializing mapper mapped class Application->application, expression 'Version' failed to locate a name ("name 'Version' is not defined"). If this is a class name, consider adding this relationship() to the class after both dependent classes have been defined.

Interestingly the first statement I execute that "triggers" the error does not even involve the classes in the message. For the record it is user_mk = User.query.filter_by(user_name='mk').first().

The part of the model that errors is a simple 1-M relationship.

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
...etc...
app = Flask(__name__)
app.config.from_object(TestConfig)  
db = SQLAlchemy(app)

class User(UserMixin, db.Model)
    __bind_key__ = 'app'
    __tablename__ = 'user'

...etc...

class Version(db.Model):
    __bind_key__ = 'app'
    __tablename__ = 'version'

    version_id = db.Column(db.Integer, primary_key=True)
    version_number = db.Column(db.Integer, nullable=False)
    release_number = db.Column(db.Integer, nullable=False)
    modification_number = db.Column(db.Integer, nullable=False, server_default=db.text("0"))
    test_status = db.Column(db.Integer, index=True)
    lifecycle = db.Column(db.Text, index=True, server_default=db.text("\"Current\""))
    timestamp = db.Column(db.DateTime, server_default=db.text("CURRENT_TIMESTAMP"))
    notes = db.Column(db.Text)

class Application(db.Model):
    __bind_key__ = 'app'
    __tablename__ = 'application'

    application_id = db.Column(db.Integer, primary_key=True)
    application_name = db.Column(db.Text)
    version_id = db.Column(db.ForeignKey('version.version_id'), index=True)
    description = db.Column(db.Text)
    notes = db.Column(db.Text)

    version = db.relationship('Version')

I cannot understand how SQLAlchemy cannot "see" the Version class from the Application class. What am I Doing wrong?

UPDATE Following the suggestion in the answer below a different error occurs.

sqlalchemy.exc.InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Triggering mapper: 'mapped class Version->version'. Original exception was: Could not determine join condition between parent/child tables on relationship Version.applications - there are no foreign keys linking these tables. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify a 'primaryjoin' expression.

The code I tried is

class Version(db.Model):
    __bind_key__ = 'app'
    __tablename__ = 'version'

    version_id = db.Column(db.Integer, primary_key=True)
    version_number = db.Column(db.Integer, nullable=False)
    release_number = db.Column(db.Integer, nullable=False)
    modification_number = db.Column(db.Integer, nullable=False, server_default=db.text("0"))
    test_status = db.Column(db.Integer, index=True)
    lifecycle = db.Column(db.Text, index=True, server_default=db.text("\"Current\""))
    timestamp = db.Column(db.DateTime, server_default=db.text("CURRENT_TIMESTAMP"))
    notes = db.Column(db.Text)

    applications = db.relationship('Application', 
                    backref='version',
                    primaryjoin='Version.version_id == Application.version_id',
                    )

class Application(db.Model):
    __bind_key__ = 'app'
    __tablename__ = 'application'

    application_id = db.Column(db.Integer, primary_key=True)
    application_name = db.Column(db.Text)
    version_id = db.Column(db.ForeignKey('version.version_id'), index=True)
    description = db.Column(db.Text)
    notes = db.Column(db.Text)

ANSWER Thanks @djnz. The answer that works is as follows, but it is not clear why. Observe that the primaryjoin clause under Version has been replaced with a foreign_keys clause.

class Version(db.Model):
    __bind_key__ = 'app'
    __tablename__ = 'version'

    version_id = db.Column(db.Integer, primary_key=True)
    version_number = db.Column(db.Integer, nullable=False)
    release_number = db.Column(db.Integer, nullable=False)
    modification_number = db.Column(db.Integer, nullable=False, server_default=db.text("0"))
    test_status = db.Column(db.Integer, index=True)
    lifecycle = db.Column(db.Text, index=True, server_default=db.text("\"Current\""))
    timestamp = db.Column(db.DateTime, server_default=db.text("CURRENT_TIMESTAMP"))
    notes = db.Column(db.Text)

    applications = db.relationship('Application', 
                    backref='version',
                    foreign_keys="Application.version_id",
                    )

class Application(db.Model):
    __bind_key__ = 'app'
    __tablename__ = 'application'

    application_id = db.Column(db.Integer, primary_key=True)
    application_name = db.Column(db.Text)
    version_id = db.Column(db.ForeignKey('version.version_id'), index=True)
    description = db.Column(db.Text)
    notes = db.Column(db.Text)
2
  • Are all models defined in a single file, or separate files? Do they all use the same db instance? Have you made sure that all models get imported/defined before first use? Commented Feb 10, 2020 at 9:41
  • Yes, all models in one file imported at the start of the script. Commented Feb 11, 2020 at 1:33

1 Answer 1

1

This is likely where backref or back_populates is needed. These are used by SQLAlchemy to map the relationship.

Using backref (on your Version model):

applications = db.relationship("Version", backref="version")

This is the same as writing:

# Version model:
applications = db.relationship("Application", back_populates="version")

# Application model:
version = db.relationship("Version", backref="applications")

This mapping then adds the parent/child reference to the model, like my_version.applications, or my_application.version

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, I have tried this and it looks like it should work but I now get a different error. I have added details to the end of the original question.
Could you try foreign_keys="Application.version_id" instead of primaryjoin to see if that works instead? I'm not too sure where to go from here sorry!
That worked, I have no idea why, the primaryjoin keyword looks equivalent to the foreign_key keyword in intent. I better hit the manuals! Thanks, I have put your answer in my question to make it easy to find.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.