Search code examples
pythonsqlalchemynestedruntimeclass-variables

Python Sqlalchemy - tablename as a variable


I am using SQLAlchemy in Python and am declaring my classes inheriting from a declarative base as follows:

from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class SomeClass(Base):
    __tablename__ = 'some_table'
    id = Column(Integer, primary_key=True)
    name =  Column(String(50))

As a user I would like to define the __tablename__ as a parameter, and not a hard-coded value , something like this:

class SomeClass(Base):
    __tablename__ = f'{environment}_some_table'
    id = Column(Integer, primary_key=True)
    name =  Column(String(50))

It is my understanding that f'{environment}_some_table' will be be evaluated when I import this package, and therefore I won't be able to modify it at a later stage (i.e. in an interactive notebook). I have a broken piece of code that tries to solve this through nested classes and encapsulation, but I do not manage to reference the instance variable of an outer class.

class Outer:
    def __init__(self, env):
        self.environment = env

    class SomeClass(Base):
        __tablename__ = f'{self.environment}_some_table'
        id = Column(Integer, primary_key=True)
        name =  Column(String(50))

I have read in a couple of SO questions that it is better not to use nested classes since no special relationship is established between these classes. So what kind of design should I use to solve this problem?

Thanks in advance!


Solution

  • you can make all your model definitions inside a function scope so the will be depended on outer arguments:

    def create_models(environment):
        class SomeClass(Base):
            __tablename__ = f'{environment}_some_table'
            id = Column(Integer, primary_key=True)
            name =  Column(String(50))
        ...
        globals().update(locals()) # update outer scope if needed
    
    ... # some time later
    create_models('cheese')
    ... # now create the db session/engine/etc ... 
    

    another choice to look at is the builtin reload method. check it out :)