Python3: Правильный способ выполнения ORM с использованием метакласса
В следующем исходном файле создан ORM Car
для представления таблицы базы данных.
Но Car.brand
после этого стал None
. Из-за того, что TableMetaCls
устанавливает для всех полей бд значение None. Как мне перенести Car.brand
в StringField()
? Как правильно это сделать? Это похоже на django ORM, пожалуйста, смотрите https://github.com/django/django/blob/main/django/db/models/base.py#L477 для справки.
class Field:
pass
class StringField(Field):
pass
class TableMetaCls(type):
def __new__(cls, name, bases, attr):
# backup field definition
field_definitions = {}
for x, y in attr.items():
if isinstance(y, Field):
field_definitions[x] = y
attr['field_definitions'] = field_definitions
# set field val to null
for x, y in attr.items():
if isinstance(y, Field):
attr[x] = None
return super(TableMetaCls, cls).__new__(cls, name, bases, attr)
class Table(metaclass=TableMetaCls):
def save(self):
pass
class Car(Table):
brand = StringField()
model = StringField()
c = Car()
c.brand = "BMW"
print(Car.brand)
Это None
, поскольку вы явно установили все Field
атрибуты на None
в __new__
метаклассе. Вы можете начать, сделав что-то вроде этого:
class Field:
pass
class StringField(Field):
pass
class TableMetaCls(type):
def __new__(mcs, name, bases, attr):
field_definitions = {}
for name, field in attr.items():
if isinstance(field, Field):
field_definitions[name] = field
field._name = name
attr["_field_definitions"] = field_definitions
return super().__new__(mcs, name, bases, attr)
class Table(metaclass=TableMetaCls):
def __init__(self):
self._data = {}
def __getattribute__(self, name):
if name in object.__getattribute__(self, "_field_definitions"):
return object.__getattribute__(self, "_data").get(name)
else:
return object.__getattribute__(self, name)
def __setattr__(self, name, value):
if name in self._field_definitions:
self._data[name] = value
else:
object.__setattr__(self, name, value)
def save(self):
pass
class Car(Table):
brand = StringField()
model = StringField()
c = Car()
c2 = Car()
c.brand = "BMW"
print(c.brand)
print(c2.brand)
print(Car.brand)
Выход:
BMW None <__main__.StringField object at 0x10393bc10>