SQLAlchemy import tables with relationships - python

I have problem with separating tables with relationships in different files. I want the tables below to be in three separate files and to import TableA in third party page, but I can not manage the load order.
In most of the time I'm receiving the following error.
sqlalchemy.exc. InvalidRequestError: When initializing mapper Mapper|TableA|tablea, expression 'TableB' failed to locate a name ("name 'TableB' is not defined"). If this is a class
name, consider adding this relationship() to the class after both dependent classes have been defined.
class TableA(Base):
__tablename__ = "tablea"
id = Column(Integer, primary_key=True)
name = Column(String)
tableB = relationship("TableB", secondary = TableC.__table__)
class TableB(Base):
__tablename__ = "tableb"
id = Column(Integer, primary_key=True)
name = Column(String)
class TableC(Base):
__tablename__ = "tableab"
tableAId = Column("table_a_id", Integer, ForeignKey("TableA.id"), primary_key=True)
tableBId = Column("table_b_id", Integer, ForeignKey("TableB.id"), primary_key=True)

This should work (note that the TableC.table is replaced with the name of the table to avoid circular module loading):
### base.py
engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(bind=engine)
Base = declarative_base(bind=engine)
### classA.py
from base import Base
from classB import TableB
class TableA(Base):
__tablename__ = 'tablea'
id = Column(Integer, primary_key=True)
name = Column(String(50))
tableBs = relationship("TableB", secondary="tableab")
#tableBs = relationship("TableB", secondary=TableC.__table__)
### classB.py
from base import Base
class TableB(Base):
__tablename__ = 'tableb'
id = Column(Integer, primary_key=True)
name = Column(String(50))
### classC.py
from base import Base
from classA import TableA
from classB import TableB
class TableC(Base):
__tablename__ = 'tableac'
tableAId = Column(Integer, ForeignKey("tablea.id"), primary_key=True, )
tableBId = Column(Integer, ForeignKey("tableb.id"), primary_key=True, )
### main.py
from base import Base, Session, engine
from classA import TableA
from classB import TableB
from classC import TableC
Base.metadata.create_all(engine)
Also I believe that the ForeignKey parameter is case sensitive, so you code might not work because "TableA.id" doe snot match "tablea" name when case-sensitive.

from sqlalchemy import Column, String, Integer
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Parent(Base):
__tablename__ = 'Parent'
ParentID = Column(Integer, primary_key=True)
Description = Column(String)
def __init__(self, ParentID, Description):
self.ParentID = ParentID
self.Description = Description
----------------------------------------------------------------------
from sqlalchemy import Column, String, Integer, ForeignKey
import Parent
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Child(Base):
__tablename__ = "Child"
ChildID = Column(Integer, primary_key=True)
Description = Column(String)
ParentID = Column('CompanyID', Integer, ForeignKey(Parent.ParentID))
def __init__(self, ChildID, Description,ParentID):
self.ChildID = ChildID
self.Description = Description
self.ParentID=ParentID

Related

session.add() and session methods does not exist

I'm using SqlAlchemy 1.3.20 and python3.8
In below code i used class sessionmaker.than i created an object.
when i call object methods such as : add() , commit() , query() and etc
i see this error TypeError: "Session' object is not callable.
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import Sessionmaker,relationship
base = declarative_base()
engine = create_engine('sqlite:///c:\\users\\alierza\\desktop\\python\\instagram\\test.db',echo=True)
class Cars(base):
__tablename__ = 'cars'
id = Column(Integer, primary_key=True)
make = Column(String(50), nullable=False)
color = Column(String(50), nullable=False)
class carOweners(base):
__tablename__ = 'carowner'
id = Column(Integer, primary_key=True)
name = Column(String(50), nullable=False)
age = Column(Integer, nullable=False)
carid = Column(Integer, ForeignKey('cars.id'))
car = relationship('Cars')
Session=sessionmaker(bind=engine)
session=Session()
base.metadata.create_all(engine)
car1=Cars(make='Ford',color='siliver')
owenr1=carOweners(name='Joe',age=20,carid=(car1.id))
session().add(car1)
session().add(owenr1)
session().commit()
its seems that methods does not exist.
Any tips or help?

Parent/child one-to-many distinguish Null vs. zero children

I have a parent child relationship as follows. I'd like to be able to distinguish between null children (e.g. information not known yet) vs. zero children. This is the approach I'm currently taking. It works, but seems a bit cumbersome. Is there a better way to go about this?
from sqlalchemy import Column, Integer, ForeignKey, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
engine = create_engine('sqlite:///')
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
children = relationship('Child', uselist=False)
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, ForeignKey('parent.id'), primary_key=True)
child_items = relationship('ChildItem')
class ChildItem(Base):
__tablename__ = 'childitems'
id = Column(Integer, ForeignKey('child.id'), primary_key=True)
Base.metadata.create_all(engine)
p = Parent()
assert(p.children is None) # Would like to be able to do something like this.
c = Child()
c.child_items.append(ChildItem())
p.children = c
assert(p.children is not None)

Additional primary key constraints on association object when specifying relationship in sqlalchemy

I have a many to many relationship that has a specific set of characteristics. I thought I could implement this in sqlalchemy with an association table as below:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy import Column, Integer, ForeignKey, Unicode, Enum
import enum
Base = declarative_base()
class Person(Base):
__tablename__ = 'person'
id = Column(Integer, primary_key=True)
name = Column(Unicode)
worksAt = relationship('Address', secondary='parelationship')
manages = relationship('Address', secondary='parelationship')
resides = relationship('Address', secondary='parelationship')
## How do I specify the additional constraint of
## parelationship.relation = Relationships.resident?
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
name = Column(Unicode)
class Relationships(enum.Enum):
resident = 1
worker = 2
manager = 3
class PersonAddressRelationship(Base):
__tablename__ = 'parelationship'
personId = Column(Integer, ForeignKey('person.id'), primary_key=True)
adressID = Column(Integer, ForeignKey('address.id'), primary_key=True)
relation = Column(Enum(Relationships), primary_key=True)
Is there a neat way of specifying the worksAt, manages, resides relationships (and equally worksHere, isManagedBy etc in the Address table)?
Either define the primaryjoin or the secondaryjoin with the additional predicate, or use a derived table as secondary.
Using a derived table:
worksAt = relationship(
'Address',
secondary=lambda:
PersonAddressRelationship.__table__.select().
where(PersonAddressRelationship.relation == Relationships.worker).
alias(),
viewonly=True)
Using primaryjoin:
manages = relationship(
'Address', secondary='parelationship',
primaryjoin=lambda:
and_(Person.id == PersonAddressRelationship.personId,
PersonAddressRelationship.relation == Relationships.manager),
viewonly=True)
Using secondaryjoin:
resides = relationship(
'Address', secondary='parelationship',
secondaryjoin=lambda:
and_(Address.id == PersonAddressRelationship.adressID,
PersonAddressRelationship.relation == Relationships.manager),
viewonly=True)
Note that in all the examples the expression is passed as a callable (a lambda), so that it can be lazily evaluated during mapper configuration.

sqlalchemy foreign key with complex match logic.

I am trying to build a database with sqlalchemy.
I have two tables : flow and krbr.
from __future__ import print_function
import numpy as np
import pandas as pd
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
import sqlalchemy_utils
from sqlalchemy_utils.types.ip_address import IPAddressType
Base = declarative_base()
## Define the tables schema
class Flow(Base):
__tablename__ = 'flow'
Id = Column(Integer, primary_key=True)
First = Column(Integer, index=True)
Protocol = Column(String(10))
Src = Column(IPAddressType, index=True)
SrcPort = Column(Integer)
Dst = Column(IPAddressType, index=True)
DstPort = Column(Integer)
GroupId = Column(Integer)
Port = Column(String(10))
VPort = Column(Integer)
IpTos = Column(String)
VlanId = Column(String)
VlanPri = Column(String)
Application = Column(String(100))
Packets = Column(Integer)
Messages = Column(Integer)
Bytes = Column(Integer)
Last = Column(Integer)
#LearnedIPs alertable
#LearnedIPs learned-ip
# u'LearnedIPs new-ips', u'LearnedIPs subnet-name',
# u'LearnedIPs timestamp-sec', u'LearnedIPs total-ips', u'SrcSubnet',
# u'DstSubnet'],
# 'MPLS Exp'
class Krbr(Base):
__tablename__ = 'krbr'
Id = Column(Integer, primary_key=True)
Src = Column(IPAddressType, index=True)
SrcPort = Column(Integer)
Dst = Column(IPAddressType, index=True)
DstPort = Column(Integer)
TimeNs = Column(Integer)
To some of the rows in flow is associated one or more rows of krbr.
A row in krbr is associated with a row in flow if:
1) they have the same values of Src, Dst, SrcPort, DstPort
2) They are close in time. i.e. np.abs(Flow.first - Krbr.TimeNs/1000000000) < threshold
I am wondering what is the right approach to create a link between the two tables. i.e. given a row of one table I want to be able to get the rows of the other table.
I do not know much of sqlalchemy. I guess that I should define a foreign key but I do not know how to enforce such a complex relationship.
Here is a sample of 'Handling Multiple Join Paths':
from sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
class Customer(Base):
__tablename__ = 'customer'
id = Column(Integer, primary_key=True)
name = Column(String)
billing_address_id = Column(Integer, ForeignKey("address.id"))
shipping_address_id = Column(Integer, ForeignKey("address.id"))
billing_address = relationship("Address")
shipping_address = relationship("Address")
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
street = Column(String)
city = Column(String)
state = Column(String)
zip = Column(String)
More info about 'Handling Multiple Join Paths' in you can find at
SQLAlchemy 0.9 Documentation

Automating sqlalchemy declarative model creation

Let’s say we have several sqlalchemy models for catalogues:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer
from sqlalchemy.orm import relationship
Base = declarative_base()
class Plane(Base):
__tablename__ = 'Plane'
plane_id = Column(Integer, primary_key=True)
class Car(Base):
__tablename__ = 'Car'
car_id = Column(Integer, primary_key=True)
Now for import/export purposes we want to relate these to external ids. So for Plane we would write:
class PlaneID(Base):
issuer = Column(String(32), primary_key=True)
external_id = Column(String(16), primary_key=True)
plane_id = Column(Integer, ForeignKey(Plane.plane_id))
plane = relationship(Plane, backref='external_ids')
A CarID model would be defined in exactly the same way.
What are possibilities to automate this process?
Maybe we could use a mixin, factory, decorator or meta class. How would we generate the dynamically named Columns then? It would be good to be able to add more Columns to the generated models as needed. For example:
class CarID(ExternalID):
valid_from = Column(Date)
You can subclass DeclarativeMeta - the metaclass used in declarative_base function:
from sqlalchemy.ext.declarative import DeclarativeMeta, declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship
class ExternalObject(DeclarativeMeta):
def __new__(mcs, name, bases, attributes):
if 'issuer' not in attributes:
attributes['issuer'] = Column(String(32), primary_key=True)
if 'external_id' not in attributes:
attributes['external_id'] = Column(String(16), primary_key=True)
if name[-2:] == 'ID':
ext_cls_name = name[:-2]
attr_rel = ext_cls_name.lower()
attr_id = '%s_id' % attr_rel
if attr_rel in attributes or attr_id in attributes:
# Some code here in case 'car' or 'car_id' attribute is defined in new class
pass
attributes[attr_id] = Column(Integer, ForeignKey('%s.%s' % (ext_cls_name, attr_id)))
attributes[attr_rel] = relationship(ext_cls_name, backref='external_ids')
new_cls = super().__new__(mcs, name, bases, attributes)
return new_cls
ExternalID = declarative_base(metaclass=ExternalObject)
After that you can create subclass from ExternalID and add another attributes like you did for CarID.

Categories