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>
Вернуться на верх