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.
Related
I seem to have a hard time locating an issue I have with the following many-to-many relationship:
class UserTable(Base):
__tablename__ = "user"
id = Column(String, primary_key=True)
name = Column(UnicodeText)
courses = relationship("CourseTable", secondary="user_course")
class CourseTable(Base):
__tablename__ = "course"
id = Column(String, primary_key=True)
title = Column(UnicodeText)
users = relationship("UserTable", secondary="user_course")
class UserCourseTable(Base):
__tablename__ = "user_course"
user_id = Column(String, ForeignKey('user.id'), primary_key=True)
course_id = Column(String, ForeignKey('course.id'), primary_key=True)
user = relationship("UserTable", backref=backref("user_course"))
course = relationship("CourseTable", backref=backref("user_course"))
When querying for User
user = await self.session.execute(
select(UserTable)
.where(UserTable.id == user_id)
)
I get the following error:
When initializing mapper mapped class UserCourseTable->user_course, expression 'CourseTable' failed to locate a name ('CourseTable'). If this is a class name, consider adding this relationship() to the <class 'app.models.db.user_course.UserCourseTable'> class after both dependent classes have been defined.
I tried everything described in their docs, but to no avail: the error still persists
Any suggestions?
Thanks!
EDIT:
SQLAlchemy==1.4.36
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!
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
I am trying to use sqlalchemy to run queries for one to many relationship. I am having trouble getting my queries to run.
class Quote(db.Model):
id = db.Column(db.Integer, primary_key=True)
description = db.Column(db.String(1000))
category = db.Column(db.String(100))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
date_added = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
class Category(db.Model):
id = db.Column(db.Integer, primary_key=True)
quote_cat = db.relationship("Quote", backref='category', lazy=True)
quote_id_ = db.Column(db.Integer, db.ForeignKey('quote.id'))
sqlalchemy.exc.ArgumentError: Mapper mapped class Category->category
could not assemble any primary key columns for mapped table 'category'
Your quote_cat backref references a property that already exists on the Quote class. Either remove this or change the backref value.
Here are the backref docs:
backref –
indicates the string name of a property to be placed on the related mapper’s class that will handle this relationship in the other direction
I've got a Python Flask app using flask.ext.sqlalchemy and apscheduler.schedulers.background. I've created a JobStore and gotten a table called apscheduler_jobs is has the following fields:
|id |next_run_time|job_state|
------------------------------
|TEXT| REAL | TEXT |
I want to relate a an SQLAlchemy Model object to that table using something like this:
from apscheduler.schedulers.background import BackgroundScheduler
scheduler = BackgroundScheduler()
scheduler.add_jobstore('sqlalchemy', url=app.config['SQLALCHEMY_DATABASE_URI'])
class Event(db.Model):
__tablename__ = "event"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(255), nullable=False)
jobs = db.relationship('scheduler', backref='apscheduler_jobs')
So I want to use the table from the APScheduler apscheduler_jobs and then associate that with a foreign key to my Event object. That last line there will basically break as "scheduler" isn't a defined SQLAlchmey model
qlalchemy.exc.InvalidRequestError: When initializing mapper Mapper|Event|event, expression 'scheduler' failed to locate a name ("name 'scheduler' is not defined"). If this is a class name, consider adding this relationship() to the <class 'project.models.Event'> class after both dependent classes have been defined.
So I think I need an inbetween Model class called "job" or something, then relate that to apscheduler_jobs, but something here still feels bad - because APScheduler is making this table up I've got no control over what's going on there - should I be concerned about that?
EDIT1:
So I created 2 models, one "Event" then one "Job", the "Job" then relates to the table apscheduler_jobs
class Job(db.Model):
__tablename__ = "job"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(255), nullable=False)
apscheduler_job_id = db.Column(db.Integer, db.ForeignKey('apscheduler_jobs.id'))
event_id = db.Column(db.Integer, db.ForeignKey('event.id'))
problem there is that when I dropped the DB and recreated it it's thrown the error:
sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'job.apscheduler_job_id' could not find table 'apscheduler_jobs' with which to generate a foreign key to target column 'id'
Now I could get around that in my database creation script, but again it still feels like I'm doing this the wrong way
EDIT2
I managed to get it to work, though this feels pretty wrong, I've now got 3 models: Event, Job, and APSchedulerJobsTable. The final model basically matches what the APScheduler apscheduler_jobs looks like. There must be a better way to do this though.
from project import db
class Event(db.Model):
__tablename__ = "event"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(255), nullable=False)
jobs = db.relationship('Job', backref='job_event')
class Job(db.Model):
__tablename__ = "job"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
apscheduler_job_id = db.Column(db.TEXT, db.ForeignKey('apscheduler_jobs.id'))
event_id = db.Column(db.Integer, db.ForeignKey('event.id'))
class APSchedulerJobsTable(db.Model):
# TODO: This feels bad man
__tablename__ = "apscheduler_jobs"
id = db.Column(db.TEXT, primary_key=True, autoincrement=True)
next_run_time = db.Column(db.REAL)
job_state = db.Column(db.TEXT)
Ok, two solutions - neither really perfect IMO:
Solution One, probably more clean - simply have a Text field in the job table that contains aspscheduler_job_ids - this is not a foreign key though but once the aspscheduler_job ID is known it's possible to go ahead and store it in the job table for later reference
class Event(db.Model):
__tablename__ = "event"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(255), nullable=False)
jobs = db.relationship('Job', backref='job_event')
class Job(db.Model):
__tablename__ = "job"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
event_id = db.Column(db.Integer, db.ForeignKey('event.id'))
apscheduler_job_id = db.Column(db.TEXT)
Catch for this one is in order to drop the full db you'll need to run this to include dropping the unmanaged table apscheduler_jobs:
db.reflect()
db.drop_all()
Solution Two, add the apscheduler table to the model itself, and then set up the foreign key:
class Event(db.Model):
__tablename__ = "event"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(255), nullable=False)
jobs = db.relationship('Job', backref='job_event')
class Job(db.Model):
__tablename__ = "job"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
event_id = db.Column(db.Integer, db.ForeignKey('event.id'))
apscheduler_job_id = db.Column(db.TEXT, db.ForeignKey('apscheduler_jobs.id'))
class APSchedulerJobsTable(db.Model):
# TODO: This feels bad man
__tablename__ = "apscheduler_jobs"
id = db.Column(db.TEXT, primary_key=True, autoincrement=True)
next_run_time = db.Column(db.REAL)
job_state = db.Column(db.TEXT)
job = db.relationship('Job', backref='job_event')