Python & SQLAlchemy many-to-many relation error after specify schema name - python

Here the code:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
AvailableModules = db.Table('available_modules',
db.Column('customer_id', db.Integer, db.ForeignKey('customers.id')),
db.Column('module_id', db.Integer, db.ForeignKey('modules.id')),
schema='tcloud_admin')
class Customer(db.Model):
__tablename__ = 'customers'
__table_args__ = {"schema":"tcloud_admin"}
id = db.Column(db.Integer, primary_key=True)
....
modules = db.relationship('Module', secondary=AvailableModules)
class Module(db.Model):
__tablename__ = 'modules'
__table_args__ = {"schema":"tcloud_admin"}
id = db.Column(db.Integer, primary_key=True)
....
Trying the above script gives me this error:
sqlalchemy.exc.NoReferencedTableError: Foreign key associated with
column 'available_modules.customer_id' could not find table
'customers' with which to generate a foreign key to target column 'id'
Without specifying the schema name everything works fine.

When using a custom schema name all foreign keys that reference a table or column in that schema must explicitly contain that schema name too.
Your ForeignKey('customers.id') references a different table customers which is not inside your custom schema. As this table does not exist at all you get the corresponding error.
To fix the error change the foreign keys:
db.ForeignKey('tcloud_admin.customers.id')
db.ForeignKey('tcloud_admin.modules.id')
This is also explained in the docs

Related

Flask SQLAlchemy could not find table with which to generate Foreign Key even though table exists

class BigBoxModel(db.Model):
__tablename__ = "bigbox"
id = db.Column(db.BigInteger, primary_key=True, autoincrement=True)
name = db.Column(db.String, unique=True, nullable=False)
vendor_id = db.Column(db.BigInteger, db.ForeignKey("vendors.id"), nullable=False)
I am trying to work with the bigbox table but keep getting the error:
Foreign key associated with column 'bigbox.vendor_id' could not find table 'vendors' with which to generate a foreign key to target column 'id'
The vendors table exists in another file. I cannot import it because that results in circular imports as there are a lot of commonly used libraries present in both files. I have also checked all the table names by running the command:
db.engine.table_names()
And the vendors table does exist but I still keep getting the same error. I am using Flask, SQLalchemy, Postgres.
You could try to use the Class name for foreign key mapping. In your BigBoxModel, you can have something like
vendor_id = db.Column(db.BigInteger, db.ForeignKey(Vendors.id), nullable=False). In this case Vendors is assumed to be the class name.

Accessing sqlalchemy Foreign Key relationship information programmatically

I'm trying to build tests for flask-sqlalchemy models to confirm they match the tables in the database. Using reflection, I can get the db tables, columns, and foreign keys. With the models I know how to check tablename and column names, but I can't figure out how to see the defined foreign key relationships programatically.
Model example:
class Example(db.Model):
__table_args__ = {'schema': 'defined_schema'}
__tablename__ = 'example'
id = db.Column(db.BigInteger, primary_key=True)
name = db.Column(db.String)
info = db.Column(db.BigInteger, db.ForeignKey(Info.id))
descr = db.Column(db.String)
Given a Model m, I've tried:
dir(m)
m.__dict__
Using sqlalchemy.inspect(model).columns.foreign_keys and a bit of string manipulation, I was able to compare model foreign key relationships to those in the DB

sqlalchemy.exc.AmbiguousForeignKeysError after Inheritance

I'm using sqlacodegen for reflecting a bunch of tables from my database.
And i'm getting the following error:
sqlalchemy.exc.AmbiguousForeignKeysError: Can't determine join between 'Employee' and 'Sales'; tables have more than one foreign key constraint relationship between them. Please specify the 'onclause' of this join explicitly.
Here's a simplified version of my tables.
I read in the documentation that I should use the foreign_keys parameter to resolve ambiguity between foreign key targets. Although, I think this problem is because of the inheritance. Could someone help me understand what is going on.
# coding: utf-8
from sqlalchemy import Column, ForeignKey, Integer
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
class Employee(Base):
__tablename__ = 'Employee'
EmployeeId = Column(Integer, primary_key=True)
class Sales(Employee):
__tablename__ = 'Sales'
EmployeeID = Column(ForeignKey('Employee.EmployeeId'), primary_key=True)
OldemployeeID = Column(ForeignKey('Employee.EmployeeId'))
employee = relationship('Employee', foreign_keys=[EmployeeID])
old_employee = relationship("Employee", foreign_keys=[OldemployeeID])
When your tables have multiple possible paths to inherit between them (Sales.EmployeeID or Sales.OldEmployeeID), SqlAlchemy doesn't know which one to use and you'll need to tell it the path explicitly, by using inherit_condition. For instance to inherit by EmployeeID:
class Sales(Employee):
...
__mapper_args__ = { "inherit_condition": EmployeeID == Employee.EmployeeId }
For the sake of example, you could also inherit by OldEmployeeID, by entering OldEmployeeID == Employee.EmployeeId - this would mean that both your Sales primary key and the Employee primary key are allowed to be different.
Just use backref and use Integer on both EmployeeID and OldemployeeID. Otherwise you will get an another error.
class Sales(Employee):
__tablename__ = 'Sales'
EmployeeID = Column(Integer, ForeignKey('Employee.EmployeeId'), primary_key=True)
OldemployeeID = Column(Integer, ForeignKey('Employee.EmployeeId'))
employee = relationship('Employee', foreign_keys=[EmployeeID], backref='Employee')
old_employee = relationship("Employee", foreign_keys=[OldemployeeID], backref='Employee')

SQLAlchemy Many-to-Many Relationship on a Single Table Error: NoReferencedTableError

I'm using Flask and SQLAlchemy.
I'm trying to reference column in the same table to create a tree structure, using additional table to store all ancestor-child connections, not only parent-child.
I've used the example here https://stackoverflow.com/a/5652169/2947812, and my code in models.py is:
# -*- coding: utf-8 -*-
from my_app import db
Cats_hierarchies = db.Table('cats_hierarchies', db.MetaData(),
db.Column('parent_id', db.Integer, db.ForeignKey('category.id')),
db.Column('category_id', db.Integer, db.ForeignKey('category.id'))
)
class Category(db.Model):
__tablename__ = 'category'
id = db.Column(db.Integer, primary_key=True)
children = db.relationship("Category",
secondary = Cats_hierarchies,
primaryjoin = Cats_hierarchies.c.category_id == id,
secondaryjoin = Cats_hierarchies.c.parent_id == id,
backref="children")
When I try to create database with from my_app import db I receive the following error message: sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'cats_hierarchies.category_id' could not find table 'category' with which to generate a foreign key to target column 'id'
What am I doing wrong?
I got rid of the error by adding
foreign_keys =
[Cats_hierarchies.c.parent_id,
Cats_hierarchies.c.category_id])
to Category.children definition.
Still don't know though why is it necessary. Found it here: https://stackoverflow.com/a/8809907/2947812

How to create viewonly field in SqlAlchemy and GeoAlchemy2?

I am trying to dynamically populate a field using SqlAlchemy 0.8.4 and GeoAlchemy2 0.2.2. The goal is to assign a District to the Facility based on the facility's position when it is read from the database. The code looks like this:
class District(Base):
__tablename__ = 'districts'
id = Column(Integer, primary_key=True)
geom = Column('geog', Geometry(geometry_type='POLYGON'), nullable=False)
class Facility(Base):
__tablename__ = 'facilities'
id = Column(Integer, primary_key=True)
pos = Column('geog', Geometry(geometry_type='POINT'), nullable=True)
district = relationship(District,
viewonly=True,
primaryjoin="District.geom.ST_Contains(Facility.pos)",
foreign_keys=[District.id])
But this gives me the following error:
ArgumentError: Could not locate any relevant foreign key columns for
primary join condition 'ST_Contains(districts.geog, facilities.geog)'
on relationship Facility.district. Ensure that referencing columns
are associated with a ForeignKey or ForeignKeyConstraint, or are
annotated in the join condition with the foreign() annotation
I would really like to avoid having foreignkey relation between these classes since the districts are constantly changing, but would like to get a facility with a district set without querying the database again.
How should I solve this?

Categories