flask sqlalchemy does not insert a foreign key using mysql - python

I'm using Flask sqlalchemy to create some tables for a database using mySQL. I have a problem when setting some foreign keys,
the tables are:
class Specific(db.Model):
code = db.Column(db.String(30), primary_key=True, index=True)
serial_number = db.Column(db.String(30), primary_key=True, index=True)
equipment_id = db.Column(db.String(30), db.ForeignKey('general.id'), index=True)
#setting relationship fields
tickets_equip_code = db.relationship('Ticket', backref='specific_code', lazy='dynamic')
tickets_serial_number = db.relationship('Ticket', backref='specific_serial, lazy='dynamic')
class Ticket(db.Model):
id = db.Column(db.String(30), primary_key=True)
solicitant = db.Column(db.String(30), db.ForeignKey('user.id'), index=True, unique=False)
#setting the foreign keys
equipment_code = db.Column(db.String(30), db.ForeignKey('specific.code'), nullable=False)
equipment_serial_number = db.Column(db.String(30), db.ForeignKey('specific.serial_number'), nullable=False)
the problem comes when I try to create all the tables using db.create_all() in the console, I get the following error:
pymysql.err.OperationalError 1822 "Failed to add the foreign key constraint. Missing index for constraint 'fk_ticket_serial_number' in the referenced table 'specific'"
I have other db Models with FKs but they seem to work well these two models are the ones causing the trouble but I can't get it. I've even tried to run the script using only one of the two FKs in the mentioned models and it runs fine; I have also tried setting both the primary keys in the Specific model using __table_args__, also I tried setting manually the FK constraints in Tickets using __table_args__ (that's why the name 'fk_ticket_serial_number' appears) but it had no effect.
Do you guys have any ideas what might be going wrong?

Related

One-To-Many database relationship Foreign Key error - SQLAlchemy

I am having trouble making a One-To-Many relationship between 'User' and 'GymObj' using a Foreign Key. In my code, a user can have only one gym objective however a gym objective can have many users. The code which I attempted seems to be correct as I followed a tutorial for it however a 'NoForeignKeysError' appears.
python code
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(200), nullable=False, unique=True)
birth_year = db.Column(db.Integer, nullable=False)
weight = db.Column(db.Integer, nullable = False)
date_added = db.Column(db.DateTime, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('gymobj.id'))
#Create a String
def __repr__(self):
return '<Username %r>' % self.username
class GymObj(db.Model):
id = db.Column(db.Integer, primary_key=True)
gym_obj = db.Column(db.String)
users = db.relationship('User', backref='user')
console
sqlalchemy.exc.NoForeignKeysError: Could not determine join condition between parent/child tables on relationship GymObj.users - there are no foreign keys linking these tables. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify a 'primaryjoin' expression.
I attempted to make a migration and push the migration in the Shell as well however the same error appeared. Any help would be much appreciated.

SqlAlchemy drop/create all duplicate relation

Using SQL Alchemy and declarative base to define two related tables
JiraBase = declarative_base(cls=_Shared)
class JiraSource(JiraBase):
id = Column(BigInteger, primary_key=True, autoincrement=True)
name = Column(String)
__tablename__ = 'jira_source'
class JiraProject(JiraBase):
id = Column(BigInteger, primary_key=True, autoincrement=True)
source = Column(BigInteger, ForeignKey('jira_source.id'), nullable=False)
project_id = Column(String, nullable=False)
project_key = Column(String, nullable=False)
name = Column(String)
__table_args__ = (Index('source', 'project_id', 'project_key', unique=True),)
__tablename__ = 'jira_project'
The idea behind the Index is that projects are uniquely identified by an id and key for a given JiraSource.
The tables are being dropped and created via
JiraBase.metadata.drop_all(bind=self.engine)
JiraBase.metadata.create_all(bind=self.engine)
This actually drops and creates tables fine; however, also throws an exception
sqlalchemy.exc.ProgrammingError: (psycopg2.errors.DuplicateTable) relation "source" already exists
[SQL: CREATE UNIQUE INDEX source ON jira_issue (issue_id)]
(Background on this error at: http://sqlalche.me/e/13/f405)
Thinking somehow because using both a ForeignKey and Index that both relate to source, is this a bad practice or something? When I comment out the Index entirely or drop the source field from it, the error goes away. Thinking that because I defined source as a foreign key that using it again in an index is bad or something?
Any idea why I'm seeing this error? For now am simply try/ignoring in code.

sqlalchemy.exc.InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers

This error happened when I tried to get access to the page. I didn't get errors when I created the tables, but seems like there are problems still.
The models are like this:
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
sell_items = db.relationship('Item', backref='user')
class Item(db.Model):
id = db.Column(db.Integer, primary_key=True)
item_name = db.Column(db.String(64), index=True)
item_image = db.Column(db.String(200), index=True)
price = db.Column(db.Float(10), index=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
user = db.relationship('User', backref='sell_items')
The whole error message is this
Triggering mapper: 'Mapper|User|user'. Original exception was: Error creating backref 'user' on relationship 'User.sell_items': property of that name exists on mapper 'Mapper|Item|item'
How can I fix this? What I want to do is to refer to username who sells the item, but I cannot. There is a problem with the relationships between the models.
When you use backref the backwards relationship is automatically created, so it should only be used in one side of the relationship. In your case, you can remove the sell_items in the User model and the User model will automatically get a relationship from Item.
To declare the relationshiop on both sides (in case you want to customize its name, for example, use back_populates='name_of_relationship_on_other_model'.
in your Item class, replace this line
user = db.relationship('User', backref='sell_items')
with this line
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
it should work that way, from there you can query like this item = Item.query.first(), then item.sell_items... to get the user who posted the item.
i hope it helps.

SQLAlchemy not cascade deleting multiple levels down

I'm a little new to SQLAlchemy. I've searched around for an answer to my question but I have found nothing that works for my situation.
In short, deleting a record in the Release model will delete all the records in the other models as long as there is no related records in TestResults. However, if there are related records in TestResult, then deleting a Release will not work. It almost seems as if deleting a parent will delete a child and the child's child but not the child's child's child. Here is some code to help highlight this:
class Release(db.Model):
__tablename__ = 'releases'
id = db.Column(db.Integer, primary_key=True)
platform_id=db.Column(db.Integer, db.ForeignKey('platforms.id'))
name = db.Column(db.String(20), unique=True)
builds = db.relationship('ReleaseBuilds', cascade='all,delete', lazy='dynamic', order_by="desc(ReleaseBuilds.date_created)")
class ReleaseBuilds(db.Model):
__tablename__='release_builds'
id = db.Column(db.Integer, primary_key=True)
release_id = db.Column(db.Integer, db.ForeignKey('releases.id'))
name = db.Column(db.String(150), nullable=False)
artifacts = db.relationship('ReleaseBuildArtifacts', cascade='all,delete', backref='builds', lazy='dynamic')
deployments = db.relationship('Deployments', cascade='all,delete', lazy='dynamic')
tests = db.relationship('Test', cascade='delete', lazy='dynamic')
class ReleaseBuildArtifacts(db.Model):
__tablename__='release_build_artifacts'
id = db.Column(db.Integer, primary_key=True)
release_build_id = db.Column(db.Integer, db.ForeignKey('release_builds.id'))
application_id = db.Column(db.Integer, db.ForeignKey('applications.id'))
rpm = db.Column(db.String(300))
build = db.relationship('ReleaseBuilds')
application = db.relationship('Application')
class Deployments(db.Model):
__tablename__ = 'deployments'
release_build_id = db.Column(db.Integer, db.ForeignKey('release_builds.id'), primary_key=True)
environment_id = db.Column(db.Integer, db.ForeignKey('environments.id'), primary_key=True)
date_deployed = db.Column(db.DateTime(timezone=False), default=datetime.datetime.utcnow)
environment = db.relationship('Environment', foreign_keys=[environment_id])
class TestType(db.Model):
__tablename__ = 'test_types'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), unique=True)
class Test(db.Model):
__tablename__ = 'tests'
id = db.Column(db.Integer, primary_key=True)
release_build_id = db.Column(db.Integer, db.ForeignKey('release_builds.id'), nullable=False)
environment_id = db.Column(db.Integer, db.ForeignKey('environments.id'), nullable=False)
test_type_id = db.Column(db.Integer, db.ForeignKey('test_types.id'))
name = db.Column(db.String(300))
environments = db.relationship('Environment', foreign_keys=[environment_id])
results = db.relationship('TestResult', cascade='all,delete', lazy='dynamic')
__table_args__ = (
ForeignKeyConstraint(['release_build_id', 'environment_id'],['deployments.release_build_id', 'deployments.environment_id']),
)
class TestResult(db.Model):
__tablename__ = 'test_results'
id = db.Column(db.Integer, primary_key=True)
test_id = db.Column(db.Integer, db.ForeignKey('tests.id'), nullable=False)
name = db.Column(db.String(500))
passed = db.Column(db.Boolean)
Any suggestions as to why this cascade delete is not working?
I came across a similar issue in our project, where we define cascades on the ORM level and also use lazy=dynamic relationships. This caused the cascade not to run on the bottom-most children.
Dynamic loading causes the relationship to return a Query object when accessed.
Delete on queries is quite limited, in order to increase performance, as documented here:
https://docs.sqlalchemy.org/en/13/orm/query.html
The method does not offer in-Python cascading of relationships - it
is assumed that ON DELETE CASCADE/SET NULL/etc. is configured for any
foreign key references which require it, otherwise the database may
emit an integrity violation if foreign key references are being
enforced.
After the DELETE, dependent objects in the Session which were impacted
by an ON DELETE may not contain the current state, or may have been
deleted. This issue is resolved once the Session is expired, which
normally occurs upon Session.commit() or can be forced by using
Session.expire_all(). Accessing an expired object whose row has been
deleted
will invoke a SELECT to locate the row; when the row is not found,
an ObjectDeletedError is raised.
Therefore a solution for your problem could be either defining cascades on the database level, or using other types of relationships.
Related question was raised here: SQLAlchemy delete doesn't cascade
EDIT: (Solution I applied is changing the loading type on query level - in options)

Flask-Migrate Alter Table Error

i've been scratching my head for a bit of time now with this error and I can't seem to figure out what's wrong. Maybe you can help?
Using Flask-Migrate i've modified my models and am attempting to migrate the database accordingly.
The error i'm running into seems to be between two specific models User and Transaction.
After running
$ python run.py db init
$ python run.py db migrate
$ python run.py db upgrade
I recieve this error:
sqlalchemy.exc.OperationalError: (_mysql_exceptions.OperationalError) (1825, "Failed to add the foreign key constraint on table 'transaction_table'. Incorrect options in FOREIGN KEY constraint 'my_database/transaction_table_ibfk_1'") [SQL: 'ALTER TABLE transaction_table ADD FOREIGN KEY(user_id) REFERENCES users (id)']
Here is how i've set up my models note the tablename override:
class User(db.Model):
__tablename__ = 'users'
id = db.Column('id', db.Integer, primary_key=True)
email = db.Column(db.String(120), unique=True, index=True)
password = db.Column('password', db.String(10))
role = db.Column('role', db.String(3))
registered_on = db.Column('registered_on', db.DateTime)
transactions = db.relationship('transaction_table', backref=db.backref('user', lazy='joined'), lazy='dynamic')
class Transaction(db.Model):
__tablename__ = 'transaction_table'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
transaction_date = db.Column('transaction_date', db.DateTime)
requested_donor_id = db.Column(db.Integer, db.ForeignKey('donor_db.id'))
I've used this guide for setting up my models with Foreign Keys and relationships.
I've used this Blog Post to help diagnose my problems to no avail. Might you know what i'm missing?
Thanks in advance.

Categories

Resources