# collection-based relationships are by default named
# "<classname>_collection"
u1 = session.query(User).first()
- print (u1.address_collection)
+ print(u1.address_collection)
Above, calling :meth:`.AutomapBase.prepare` while passing along the
:paramref:`.AutomapBase.prepare.reflect` parameter indicates that the
from sqlalchemy import create_engine, MetaData, Table, Column, ForeignKey
from sqlalchemy.ext.automap import automap_base
+
engine = create_engine("sqlite:///mydatabase.db")
# produce our own MetaData object
# we can reflect it ourselves from a database, using options
# such as 'only' to limit what tables we look at...
- metadata.reflect(engine, only=['user', 'address'])
+ metadata.reflect(engine, only=["user", "address"])
# ... or just define our own Table objects with it (or combine both)
- Table('user_order', metadata,
- Column('id', Integer, primary_key=True),
- Column('user_id', ForeignKey('user.id'))
- )
+ Table(
+ "user_order",
+ metadata,
+ Column("id", Integer, primary_key=True),
+ Column("user_id", ForeignKey("user.id")),
+ )
# we can then produce a set of mappings from this MetaData.
Base = automap_base(metadata=metadata)
Base.prepare()
# mapped classes are ready
- User, Address, Order = Base.classes.user, Base.classes.address,\
- Base.classes.user_order
+ User = Base.classes.user
+ Address = Base.classes.address
+ Order = Base.classes.user_order
.. _automap_by_module:
Base.metadata.create_all(e)
+
def module_name_for_table(cls, tablename, table):
if table.schema is not None:
return f"mymodule.{table.schema}"
else:
return f"mymodule.default"
+
Base = automap_base()
Base.prepare(e, modulename_for_table=module_name_for_table)
Base.prepare(e, schema="test_schema", modulename_for_table=module_name_for_table)
Base.prepare(e, schema="test_schema_2", modulename_for_table=module_name_for_table)
-
The same named-classes are organized into a hierarchical collection available
at :attr:`.AutomapBase.by_module`. This collection is traversed using the
dot-separated name of a particular package/module down into the desired
# automap base
Base = automap_base()
+
# pre-declare User for the 'user' table
class User(Base):
- __tablename__ = 'user'
+ __tablename__ = "user"
# override schema elements like Columns
- user_name = Column('name', String)
+ user_name = Column("name", String)
# override relationships too, if desired.
# we must use the same name that automap would use for the
# generate for "address"
address_collection = relationship("address", collection_class=set)
+
# reflect
engine = create_engine("sqlite:///mydatabase.db")
Base.prepare(autoload_with=engine)
Address = Base.classes.address
u1 = session.query(User).first()
- print (u1.address_collection)
+ print(u1.address_collection)
# the backref is still there:
a1 = session.query(Address).first()
- print (a1.user)
+ print(a1.user)
Above, one of the more intricate details is that we illustrated overriding
one of the :func:`_orm.relationship` objects that automap would have created.
import re
import inflect
+
def camelize_classname(base, tablename, table):
- "Produce a 'camelized' class name, e.g. "
+ "Produce a 'camelized' class name, e.g."
"'words_and_underscores' -> 'WordsAndUnderscores'"
- return str(tablename[0].upper() + \
- re.sub(r'_([a-z])', lambda m: m.group(1).upper(), tablename[1:]))
+ return str(
+ tablename[0].upper()
+ + re.sub(
+ r"_([a-z])",
+ lambda m: m.group(1).upper(),
+ tablename[1:],
+ )
+ )
+
_pluralizer = inflect.engine()
+
+
def pluralize_collection(base, local_cls, referred_cls, constraint):
- "Produce an 'uncamelized', 'pluralized' class name, e.g. "
+ "Produce an 'uncamelized', 'pluralized' class name, e.g."
"'SomeTerm' -> 'some_terms'"
referred_name = referred_cls.__name__
- uncamelized = re.sub(r'[A-Z]',
- lambda m: "_%s" % m.group(0).lower(),
- referred_name)[1:]
+ uncamelized = re.sub(
+ r"[A-Z]",
+ lambda m: "_%s" % m.group(0).lower(),
+ referred_name,
+ )[1:]
pluralized = _pluralizer.plural(uncamelized)
return pluralized
+
from sqlalchemy.ext.automap import automap_base
Base = automap_base()
engine = create_engine("sqlite:///mydatabase.db")
- Base.prepare(autoload_with=engine,
- classname_for_table=camelize_classname,
- name_for_collection_relationship=pluralize_collection
- )
+ Base.prepare(
+ autoload_with=engine,
+ classname_for_table=camelize_classname,
+ name_for_collection_relationship=pluralize_collection,
+ )
From the above mapping, we would now have classes ``User`` and ``Address``,
where the collection from ``User`` to ``Address`` is called
options along to all one-to-many relationships::
from sqlalchemy.ext.automap import generate_relationship
+ from sqlalchemy.orm import interfaces
+
- def _gen_relationship(base, direction, return_fn,
- attrname, local_cls, referred_cls, **kw):
+ def _gen_relationship(
+ base, direction, return_fn, attrname, local_cls, referred_cls, **kw
+ ):
if direction is interfaces.ONETOMANY:
- kw['cascade'] = 'all, delete-orphan'
- kw['passive_deletes'] = True
+ kw["cascade"] = "all, delete-orphan"
+ kw["passive_deletes"] = True
# make use of the built-in function to actually return
# the result.
- return generate_relationship(base, direction, return_fn,
- attrname, local_cls, referred_cls, **kw)
+ return generate_relationship(
+ base, direction, return_fn, attrname, local_cls, referred_cls, **kw
+ )
+
from sqlalchemy.ext.automap import automap_base
from sqlalchemy import create_engine
Base = automap_base()
engine = create_engine("sqlite:///mydatabase.db")
- Base.prepare(autoload_with=engine,
- generate_relationship=_gen_relationship)
+ Base.prepare(autoload_with=engine, generate_relationship=_gen_relationship)
Many-to-Many relationships
--------------------------
classes given as follows::
class Employee(Base):
- __tablename__ = 'employee'
+ __tablename__ = "employee"
id = Column(Integer, primary_key=True)
type = Column(String(50))
__mapper_args__ = {
- 'polymorphic_identity':'employee', 'polymorphic_on': type
+ "polymorphic_identity": "employee",
+ "polymorphic_on": type,
}
+
class Engineer(Employee):
- __tablename__ = 'engineer'
- id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
+ __tablename__ = "engineer"
+ id = Column(Integer, ForeignKey("employee.id"), primary_key=True)
__mapper_args__ = {
- 'polymorphic_identity':'engineer',
+ "polymorphic_identity": "engineer",
}
The foreign key from ``Engineer`` to ``Employee`` is used not for a
SQLAlchemy can guess::
class Employee(Base):
- __tablename__ = 'employee'
+ __tablename__ = "employee"
id = Column(Integer, primary_key=True)
type = Column(String(50))
__mapper_args__ = {
- 'polymorphic_identity':'employee', 'polymorphic_on':type
+ "polymorphic_identity": "employee",
+ "polymorphic_on": type,
}
+
class Engineer(Employee):
- __tablename__ = 'engineer'
- id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
- favorite_employee_id = Column(Integer, ForeignKey('employee.id'))
+ __tablename__ = "engineer"
+ id = Column(Integer, ForeignKey("employee.id"), primary_key=True)
+ favorite_employee_id = Column(Integer, ForeignKey("employee.id"))
- favorite_employee = relationship(Employee,
- foreign_keys=favorite_employee_id)
+ favorite_employee = relationship(Employee, foreign_keys=favorite_employee_id)
__mapper_args__ = {
- 'polymorphic_identity':'engineer',
- 'inherit_condition': id == Employee.id
+ "polymorphic_identity": "engineer",
+ "inherit_condition": id == Employee.id,
}
Handling Simple Naming Conflicts
local_table = local_cls.__table__
if name in local_table.columns:
newname = name + "_"
- warnings.warn(
- "Already detected name %s present. using %s" %
- (name, newname))
+ warnings.warn("Already detected name %s present. using %s" % (name, newname))
return newname
return name
- Base.prepare(autoload_with=engine,
- name_for_scalar_relationship=name_for_scalar_relationship)
+ Base.prepare(
+ autoload_with=engine,
+ name_for_scalar_relationship=name_for_scalar_relationship,
+ )
Alternatively, we can change the name on the column side. The columns
that are mapped can be modified using the technique described at
Base = automap_base()
+
class TableB(Base):
- __tablename__ = 'table_b'
- _table_a = Column('table_a', ForeignKey('table_a.id'))
+ __tablename__ = "table_b"
+ _table_a = Column("table_a", ForeignKey("table_a.id"))
- Base.prepare(autoload_with=engine)
+ Base.prepare(autoload_with=engine)
Using Automap with Explicit Declarations
========================================
Base = automap_base()
+
class User(Base):
- __tablename__ = 'user'
+ __tablename__ = "user"
id = Column(Integer, primary_key=True)
name = Column(String)
+
class Address(Base):
- __tablename__ = 'address'
+ __tablename__ = "address"
id = Column(Integer, primary_key=True)
email = Column(String)
- user_id = Column(ForeignKey('user.id'))
+ user_id = Column(ForeignKey("user.id"))
+
# produce relationships
Base.prepare()
# mapping is complete, with "address_collection" and
# "user" relationships
- a1 = Address(email='u1')
- a2 = Address(email='u2')
+ a1 = Address(email="u1")
+ a2 = Address(email="u2")
u1 = User(address_collection=[a1, a2])
assert a1.user is u1
@event.listens_for(Base.metadata, "column_reflect")
def column_reflect(inspector, table, column_info):
# set column.key = "attr_<lower_case_name>"
- column_info['key'] = "attr_%s" % column_info['name'].lower()
+ column_info["key"] = "attr_%s" % column_info["name"].lower()
+
# run reflection
Base.prepare(autoload_with=engine)