SQLAlchemy error relation "table_name" does not exist - python

Im trying to build tables with many-to-many relationship from my models file, but I'm getting error:
relation "Cities" does not exist
I think that there is an issue with my many-to-many relationship because one-to-many worked fine.
Models.py file:
from sqlalchemy import Column, String, Integer, Table
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import backref, relationship
from sqlalchemy.sql.schema import ForeignKey
base = declarative_base()
cities_sensors = Table('cities_sensors', base.metadata,
Column('cities_id', ForeignKey('Cities.id')),
Column('sensors_id', ForeignKey('Sensors.id'))
)
class Cities(base):
__tablename__ = 'Cities'
id = Column(Integer, unique=True, primary_key=True)
name = Column(String)
sensors = relationship(
'Sensors', secondary=cities_sensors)
class Sensors(base):
__tablename__ = 'Sensors'
id = Column(Integer, unique=True, primary_key=True)
name = Column(String)
unit = Column(String)
db_init.py file:
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, session
from sqlalchemy.orm.session import Session
from models import Cities, Sensors
from sqlalchemy.ext.declarative import declarative_base
db_string = "postgresql://postgres:1234#localhost:5438"
db = create_engine(db_string)
base = declarative_base()
Session = sessionmaker(db)
session = Session()
base.metadata.create_all(db)
czestochowa_city = Cities(name="Czestochowa")
myszkow_city = Cities(name="Myszkow")
krzepice_city = Cities(name="Krzepice")
temperature_sensor = Sensors(name="temperature",
unit="Celsius")
humidity_sensor = Sensors(name="humidity",
unit="precentage")
pollution_sensor = Sensors(name="pollution",
unit="PM2.5")
session.add(czestochowa_city)
session.add(myszkow_city)
session.add(krzepice_city)
session.add(temperature_sensor)
session.add(humidity_sensor)
session.add(pollution_sensor)
session.commit()
Do you guys see what I'm doing here wrong?

Related

sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column could not find table

Im trying to create a relationship between two tables which are in separated classes.
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(50))
age = Column(Integer)
So I want to create a table called order which FK is the user id.
I did this:
from sqlalchemy import (Column, Float, ForeignKey, Integer, String,
create_engine)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, sessionmaker
engine = create_engine(
"mysql+pymysql://root:admin#localhost/test", echo=False)
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base()
class Order(Base):
__tablename__ = 'order'
product = Column(String(50))
price = Column(Float)
user_id = Column(
Integer,
ForeignKey('user.id', ondelete='CASCADE'), primary_key=True,
nullable=False,
# no need to add index=True, all FKs have indexes
)
cliente = relationship('User', foreign_keys='Order.user_id')
Base.metadata.create_all(engine)
I get this error:
sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'order.user_id' could not find table 'user' with which to generate a foreign key to target column 'id'
you need to add db.relationship in User table not in order table hopefully you get this useful.

Sqlalchemy: self-referential many-to-many relationship with extra column in relationship table

I'm trying to create a self-referential many-to-many relationship table with an extra column called sort_order:
from sqlalchemy import Integer, ForeignKey, String, Column, Table
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.orderinglist import ordering_list
Base = declarative_base()
class Node2Node(Base):
__tablename__ = "NodeToNode"
left_node_id = Column(Integer, ForeignKey("Node.id"), primary_key=True)
right_node_id = Column(Integer, ForeignKey("Node.id"), primary_key=True)
sort_order = Column(Integer, nullable=False)
class Node(Base):
__tablename__ = "Node"
id = Column(Integer, primary_key=True)
label = Column(String)
# Many To Many with Node
right_nodes = relationship(
"Node",
secondary="NodeToNode",
primaryjoin="Node.id==NodeToNode.c.left_node_id",
secondaryjoin="Node.id==NodeToNode.c.right_node_id",
backref="left_nodes",
order_by="NodeToNode.c.sort_order",
)
def __repr__(self):
return f"<Node: {self.label}>"
When I run the following script I get an error saying NOT NULL constraint failed: NodeToNode.sort_order:
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
engine = create_engine("sqlite:///practice.sqlite3")
session = Session(bind=engine)
# Build tables
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
# Load in data
nodes = [
Node(label="A"),
Node(label="B"),
Node(label="C"),
Node(label="D"),
Node(label="E"),
]
session.add_all(nodes)
session.commit()
nodes[0].right_nodes = [nodes[3], nodes[1], nodes[2]]
nodes[0].left_nodes = [nodes[4]]
session.add_all(nodes)
session.commit()
# Display data
print("Nodes: {}".format(nodes))
print("Node A right nodes: {}".format(nodes[0].right_nodes))
print("Node A left nodes: {}".format(nodes[0].left_nodes))
session.close()
How can I set this sort_order key based on the item's index in the list?
Use Self-referential many-to-many relationship with Association Object.
See example at https://stackoverflow.com/a/62281276/9387542

Self-Referential Many-to-Many Relationship with Association Proxy in SQLAlchemy

I'm trying to create a Self-Referential Many-to-Many Relationship. The example outlined in the SQLAlchemy documentation works great. Here are the models I created:
from sqlalchemy import Integer, ForeignKey, String, Column, Table
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
Table('NodeToNode', Base.metadata,
Column('leftNodeId', Integer, ForeignKey('Node.id'), primary_key=True),
Column('rightNodeId', Integer, ForeignKey('Node.id'), primary_key=True)
)
class Node(Base):
__tablename__ = 'Node'
id = Column(Integer, primary_key=True)
label = Column(String)
rightNodes = relationship('Node',
secondary='NodeToNode',
primaryjoin='Node.id==NodeToNode.c.leftNodeId',
secondaryjoin='Node.id==NodeToNode.c.rightNodeId',
backref='leftNodes'
)
And the script for adding data in:
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
engine = create_engine('sqlite:///practice.sqlite3')
session = Session(bind=engine)
nodes = [
Node(label='A'),
Node(label='B'),
Node(label='C'),
Node(label='D'),
Node(label='E'),
]
nodes[0].rightNodes = [nodes[1], nodes[3], nodes[2]]
nodes[0].leftNodes = [nodes[4]]
session.add_all(nodes)
session.commit()
I want to add a column to the association table so I'd assume I need to convert the association table to its own class:
class NodeToNode(Base):
__tablename__ = 'NodeToNode'
leftNodeId = Column(Integer, ForeignKey('Node.id', onupdate='CASCADE'), primary_key=True)
rightNodeId = Column(Integer, ForeignKey('Node.id', onupdate='CASCADE'), primary_key=True)
sortOrder = Column(Integer, nullable=False)
This, however, results in the following error:
sqlalchemy.exc.InvalidRequestError: Class <class 'models.node.NodeToNode'> does not have a mapped column named 'c'
Any idea what I'm doing wrong here?

SQLAlchemy association data via related class constructor

I have this design
# coding: utf-8
from sqlalchemy import Column, VARCHAR, ForeignKey, create_engine
from sqlalchemy.dialects.mysql import INTEGER, TINYINT
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.inspection import inspect
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.associationproxy import association_proxy
engine = create_engine('mysql://root:toor#localhost/test', echo=True)
Model = declarative_base()
Session = sessionmaker(bind=engine)
session = Session()
class A(Model):
__tablename__ = 'A'
id = Column(INTEGER(unsigned=True), primary_key=True)
name = Column(VARCHAR(32), nullable=False, index=True)
class AB(Model):
__tablename__ = 'AB'
A_id = Column(INTEGER(10, unsigned=True), ForeignKey('A.id'), nullable=False, primary_key=True)
B_id = Column(INTEGER(10, unsigned=True), ForeignKey('B.id'), nullable=False, primary_key=True)
type = Column(TINYINT(3, unsigned=True), nullable=False)
A_rel = relationship(
"A",
foreign_keys=[A_id]
)
B_rel = relationship(
"B",
foreign_keys=[B_id],
)
mapper_AB = inspect(AB)
class B(Model):
__tablename__ = 'B'
id = Column(INTEGER(10, unsigned=True), primary_key=True)
As = relationship("A", secondary=mapper_AB.local_table, uselist=False)
ABs = relationship("AB")
type = association_proxy('ABs', 'type')
Model.metadata.create_all(engine)
a = A(
name="test",
)
session.add(a)
session.commit()
b = B(
As=a,
type=2
)
print(b.type)
session.add(b)
session.commit()
This obviously fails, but I am trying to simplify the design by adding the AB extra information (type) via one (B) of the related classes constructor.
I have gone through tons of SQLAlchemy documentation, and even lost myself inside the source code but to no avail. The 3 table design of the database cannot be modified, as is part of a bigger system and belongs to another project. My goal is to map those table into a more simplified design for further development where this models will be used.
Is this possible using SQLAlchemy mechanisms with declarative style?

Load subset of joined columns in SQLAlchemy

I'm trying to load a subset of columns from multiple joined tables in SQLAlchemy and can't figure out the magic syntax.
Here's a simple example of what I'm trying to do. It results in an error (below):
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, load_only
Base = declarative_base()
class Table1(Base):
__tablename__ = 'table1'
table1_id = Column(Integer, primary_key=True)
table1_val = Column(String)
r1 = relationship('Table2', backref = 'r2')
class Table2(Base):
__tablename__ = 'table2'
table2_id = Column(Integer, ForeignKey('table1.table1_id'), primary_key=True)
table2_val = Column(String)
from sqlalchemy.orm import sessionmaker
some_engine = create_engine('postgresql://scott:tiger#localhost/')
Session = sessionmaker(bind=some_engine)
session = Session()
query = session.query(Table1).join(Table2).options(load_only('table1_val','table2_val'))
ArgumentError: Can't find property named 'table2_val' on the mapped entity Mapper|Table1|table1 in this Query.
How do I pick and choose columns from these multiple tables?
Question was answered at [https://bitbucket.org/zzzeek/sqlalchemy/issues/3679/multiple-load_only-in-queryoptions-ignore]
Here is the corrected code:
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import joinedload, Load, relationship, load_only
Base = declarative_base()
class Table1(Base):
__tablename__ = 'table1'
global_id = Column(Integer, primary_key=True)
table1_val1 = Column(String)
table1_val2 = Column(String)
r1 = relationship('Table2', backref = 'r2')
class Table2(Base):
__tablename__ = 'table2'
global_id = Column(Integer, ForeignKey('table1.global_id'), primary_key=True)
table2_val1 = Column(String)
table2_val2 = Column(String)
from sqlalchemy.orm import sessionmaker
some_engine = create_engine('sqlite://')
Base.metadata.create_all(some_engine)
Session = sessionmaker(bind=some_engine)
session = Session()
session.add(Table1(table1_val1='1val1',table1_val2='1val2',r1=[Table2(table2_val1='2val1', table2_val2='2val2')]))
session.commit() # expires the attribute from the session
query = session.query(Table1).options(
# note that the 'load_only()' is applied to the 'joinedload' path, not
# put on its own Load() path
joinedload('r1',innerjoin=True).load_only('table2_val1'),
Load(Table1).load_only('table1_val1'))
foo = query.all()
assert 'table1_val2' not in foo[0].__dict__
assert 'table2_val2' not in foo[0].r1[0].__dict__

Categories

Resources