Flask SQLAlchemy cannot find a related class - python

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)

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

Related

SqlAlchemy mapper mapped class falied to locate

I have two tables one to many relationship. I am using flask_sqlalchemy. The parent table is being created but can't child table got an error. I am having init.py in my models folder.
Parent Table:
class Chalans(db.Model):
__tablename__ = "chalans"
create_time = db.Column(db.DateTime)
chalan_id = db.Column(db.String(20), primary_key=True, nullable=False)
customer_id = db.Column(db.String(20))
.....
chalan_details = db.relationship("ChalanDetails", backref="chalans", lazy="dynamic")
Child Table:
class ChalanDetails(db.Model):
__tablename__ = "chalan_details"
create_time = db.Column(db.DateTime)
chalan_id = db.Column(db.String(20), db.ForeignKey("chalans.chalan_id"), primary_key=True, nullable=False)
chalan_row = db.Column(db.Integer, primary_key=True, nullable=False)
....
remarks = db.Column(db.String(200))
I am having this error below:
sqlalchemy.exc.InvalidRequestError: When initializing mapper mapped class Chalans->chalans, expression 'ChalanDetails' failed to locate a name ('ChalanDetails'). If
this is a class name, consider adding this relationship() to the <class 'models.chalans.Chalans'> class after both dependent classes have been defined.
After importing ChalanDetails to Chalans.py, it is working perfectly.

Flask SQL: foreign keys and OnUpdate

I have three SQL tables. Two are independent of each other and third that will have 2 columns (among others) each with relevant id from the first two tables
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
import datetime
class Dad(db.Model):
__tablename__ = "dad"
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
name = db.Column(db.String, unique=True)
children = db.relationship('Children', backref='dad', lazy='dynamic')
class Mom(db.Model):
__tablename__ = "mom"
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
name = db.Column(db.String, unique=True)
children = db.relationship('Children', backref='mom', lazy='dynamic')
class Children(db.Model):
__tablename__ = "children"
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
name = db.Column(db.String, unique=True)
dad_name = db.Column(db.String)
mom_name = db.Column(db.String)
dad_id = db.Column(db.Integer, db.ForeignKey('dad.id'))
mom_id = db.Column(db.Integer, db.ForeignKey('mom.id'))
created_at = db.Column(db.DateTime(6), default=datetime.datetime.utcnow)
updated_at= db.Column(db.DateTime(6), default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
I have 2 issues that I need help with
If I do dad.children.append({'name':'Joe', 'dad_name':'Bill', 'mom_name':'Samantha'}) it attaches the dad.id automatically but not the mom.id. I want it to attach mom.id as well based on her name even if I create it from dad.
When I try to update the record from pgAdmin, it should update the updated_at column with the update time but it doesn't.
Thanks!

Flask - SQLAlchemy many to many causes sqlalchemy.orm.exc.FlushError

class Show(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(200), unique=True, nullable=False)
studio = db.relationship("ShowStudio", backref="show", cascade="delete")
class Studio(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), unique=True, nullable=False)
show = db.relationship("ShowStudio", backref="studio", cascade="delete")
class ShowStudio(db.Model):
show_id = db.Column(db.Integer, db.ForeignKey(Show.id, ondelete="CASCADE"), primary_key=True)
studio_id = db.Column(db.Integer, db.ForeignKey(Studio.id, ondelete="CASCADE"), primary_key=True)
studio = Studio(name="asd")
db.session.add(studio)
s = Show(title="a", studio=[studio])
db.session.flush()
db.session.add(s)
db.session.commit()
When I run it, it throws
sqlalchemy.orm.exc.FlushError: Attempting to flush an item of type as a member of collection "Studio.show". Expected an object of type or a polymorphic subclass of this type.
I follow the answer from here. I do not understand what cause the error. Any helps are welcome.
There'd seem to be a little mixup between a many to many relationship and using the association object pattern (which is a variant of many to many). Given the way you've configured your models Show.studio is actually a one to many relationship with ShowStudio, and so it expects a collection of ShowStudio objects, not Studio:
studio = Studio(name="asd")
db.session.add(studio)
showstudio = ShowStudio(studio=studio)
# You've disabled save-update cascade, so you have to
# add the association object to the session manually!
db.session.add(showstudio)
s = Show(title="a", studio=[showstudio])
db.session.add(s)
db.session.commit()
For your original attempt to work you'd define a many to many relationship between Show and Studio using the table underlying ShowStudio as the secondary:
class Show(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(200), unique=True, nullable=False)
studio = db.relationship("Studio", secondary="show_studio",
back_populates="show")
class Studio(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), unique=True, nullable=False)
show = db.relationship("Show", secondary="show_studio",
back_populates="studio")
class ShowStudio(db.Model):
show_id = db.Column(db.Integer, db.ForeignKey(Show.id, ondelete="CASCADE"),
primary_key=True)
studio_id = db.Column(db.Integer, db.ForeignKey(Studio.id, ondelete="CASCADE"),
primary_key=True)
Since there's no explicit __tablename__ in ShowStudio Flask-SQLAlchemy automatically sets it for you to show_studio.

Flask models: access extra properties of many to many relationship

In my models.py in a flask app, I have the following tables:
class PackageBuild(db.Model, helpers.Serializer):
__tablename__ = "package_build"
package_id = db.Column(db.Integer, db.ForeignKey('package.id'))
build_id = db.Column(db.Integer, db.ForeignKey('build.id'))
git_hash = db.Column(db.Text)
version = db.Column(db.Text)
class Build(db.Model):
id = db.Column(db.Integer, primary_key=True)
packages = db.relationship(
'Package',
secondary='package_build',
back_populates='builds'
)
class Package(db.Model):
id = db.Column(db.Integer, primary_key=True)
builds = db.relationship(
'Build',
secondary='package_build',
back_populates='packages'
)
I know I can access properties of the related table:
build.packages[0].id
But how can I access properties (e.g. git_hash) of the intermediate table (ideally by using build instance)?

Can't create records in SQLAlchemy due to One or more mappers failed to initialize

I have a model file (simplified)
Repos have single user, and users can have multiple repos.
class Repo(Base):
__tablename__ = "repos"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(512), unique=True)
user_id = Column(Integer, ForeignKey('users.id'))
user = db.relationship("User", back_populates="users")
class User(Base):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(200), unique=True)
repos = db.relationship("User", back_populates="repos")
When I try to insert a record I get the error:
One or more mappers failed to initialize - can't proceed with initialization of other mappers. Original exception was: Mapper 'Mapper|User|users' has no property 'users'
How can I fix my model?
back_populates for user relationship should be repos, and for repos relationship it should be user
class Repo(Base):
__tablename__ = "repos"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(512), unique=True)
user_id = Column(Integer, ForeignKey('users.id'))
user = db.relationship("User", back_populates="repos")
class User(Base):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(200), unique=True)
repos = db.relationship("Repo", back_populates="user")

Categories

Resources