python metaclass and sqlalchemy declareative

python metaclass and sqlalchemy declareative

Metaclasses are rarely used unless they are libraries, but they are used in SQLAlchemy, so I will summarize them for reference only.

A metaclass is a class type. In the case of python, the type of the user-defined class is basically type.

>>> class A(object):
>>>     pass
>>>
>>> type(A)
type

Metaclasses other than type may be used for special purposes.

A familiar use of metaclasses is in SQLAlchemy's declarative.

>>> from sqlalchemy.ext.declarative import declarative_base
>>> Base = declarative_base()
>>> type(Base)
<class 'sqlalchemy.ext.declarative.api.DeclarativeMeta'>

With declarative, the class definition is automatically linked to the table definition.

class User(Base):
    __tablename__ = 'user_account'

    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(Varchar(100))

Internally, it uses its own metaclass called sqlalchemy.ext.declarative.api.DeclarativeMeta, and hooks the process at the time of class definition to perform mapping process.

The definition of sqlalchemy.ext.declarative.api.DeclarativeMeta is as follows. init is called when a class that inherits Base is created, and the class and table are linked in this.

sqlalchemy/ext/declarative/api.py


class DeclarativeMeta(type):
    def __init__(cls, classname, bases, dict_):
        if '_decl_class_registry' not in cls.__dict__:
            _as_declarative(cls, classname, cls.__dict__)
        type.__init__(cls, classname, bases, dict_)

    def __setattr__(cls, key, value):
        _add_attribute(cls, key, value)

In python, it seems that using a metaclass is a relatively common method when you want to do something automatically from the class definition. For example, the Form class of wtforms does much the same thing.

Depending on the use case, you may want to stop this process. Let's consider a use case such as associating a Table object created by reflection from DB with a class created by declarative_base. In such cases, the following code can be used.

from sqlalchemy import MetaData, Table
from sqlalchemy.ext.declarative import api, declarative_base
from sqlalchemy.ext.declarative.api import DeclarativeMeta


class_registry = {}
metadata = MetaData()
Base = declarative_base(class_registry=class_registry,
                        metadata=MetaData())


class MyMetaClass(DeclarativeMeta):
    def __init__(cls, classname, bases, dict_):
        #Do not associate with the table
        type.__init__(cls, classname, bases, dict_)

    @classmethod
    def create_class(cls, table_name, class_name, dbsession):
        tableobj = Table(table_name, metadata, autoload=True,
                         autoload_with=dbsession.bind)
        class_ = MyMetaClass(class_name, (Base), {})
        #Explicitly associate with the table below.
        class_.__tablename__ = tablename
        class_.__table__ = tableobj
        for c in tableobj.columns:
            setattr(class_, c.name, c)
        api.instrument_declarative(class_, class_registry, metadata)
        return class_

Recommended Posts

python metaclass and sqlalchemy declareative
Python3 metaclass memo
[python] Compress and decompress
Batch design and python
Python iterators and generators
Python packages and modules
Vue-Cli and Python integration
Ruby, Python and map
Use SQLAlchemy and multiprocessing
python input and output
Metaclass and is instance
Python3, venv and Ansible
Python asyncio and ContextVar
Encryption and decryption with Python
3-3, Python strings and character codes
Python 2 series and 3 series (Anaconda edition)
Python and hardware-Using RS232C with Python-
Python on Ruby and angry Ruby on Python
Python indentation and string format
Python real division (/) and integer division (//)
Å (Ongustromu) and NFC @ Python
Understand Python packages and modules
[Python] How to play with class variables with decorator and metaclass
# 2 [python3] Separation and comment out
Python shallow copy and deep copy
How to connect to various DBs from Python (PEP 249) and SQLAlchemy
Python and ruby slice memo
Python installation and basic grammar
I compared Java and Python!
Python shallow and deep copy
[Python] SQLAlchemy error avoidance memorandum
About Python, len () and randint ()
About Python datetime and timezone
Install Python 3.7 and Django 3.0 (CentOS)
Python environment construction and TensorFlow
Python class variables and instance variables
Ruby and Python syntax ~ branch ~
[Python] Python and security-① What is Python?
Stack and Queue in Python
Fibonacci and prime implementations (python)
Python basics: conditions and iterations
Python bitwise operator and OR
Python debug and test module
Python list and tuples and commas
Python variables and object IDs
Python list comprehensions and generators
About Python and regular expressions
group_by with sqlalchemy and sum
python with pyenv and venv
How to write a metaclass that supports both python2 and python3
Unittest and CI in Python
Maxout description and implementation (Python)
[python] Get quotient and remainder
Python 3 sorted and comparison functions
[Python] Depth-first search and breadth-first search
Identity and equivalence Python is and ==
Source installation and installation of Python
Python or and and operator trap
Challenge Python3 and Selenium Webdriver
About Python and os operations
Python higher-order functions and comprehensions