Django queryset monkeypatching для добавления нового атрибута к возвращаемым моделям в объекте QuerySet
Я использую Django 3.2
У меня есть такая модель:
class MyModel(models.Model): last_valid_field_values = models.TextField(help_text='JSON-поле с именами полей и значениями') # ...
 Я хочу иметь возможность monkeypatch моих запросов, чтобы при получении экземпляров MyModel, я мог добавить атрибут last_values_dict - который является просто загруженным JSON из last_valid_field_values
Так что у меня будет что-то вроде этого (псевдокод):
def callback_func(instance):
    instance.last_values_dict = json.loads(instance.last_valid_field_values)
    
    
MyModel.objects.all().apply_some_function_to_monkey_patch(callback_func)
Как я могу это сделать? Я также думаю, что возможно это можно сделать через генератор, итерирующий QuerySet?
 Вы можете подкласс QuerySet для реализации apply_some_function_to_monkey_patch и переопределить _fetch_all для запуска функции обратного вызова, аналогично тому, как QuerySet.prefetch_related  реализовано . Вам также необходимо переопределить __init__ и _clone для работы с фильтрами.
class MyQuerySet(models.QuerySet):
    def __init__(self, model=None, query=None, using=None, hints=None):
        super().__init__(model=model, query=query, using=using, hints=hints)
        self._callback_funcs = ()
        self._callback_done = False
    def apply_some_function_to_monkey_patch(self, *callback_funcs):
        qs = self._chain()
        qs._callback_funcs = qs._callback_funcs + callback_funcs
        return qs
    def _callback(self):
        for callback_func in self._callback_funcs:
            for item in self._result_cache:
                callback_func(item)
        self._callback_done = True
    def _clone(self):
        clone = super()._clone()
        clone._callback_funcs = self._callback_funcs[:]
        return clone
    def _fetch_all(self):
        super()._fetch_all()
        if self._callback_funcs and not self._callback_done:
            self._callback()
Использование:
class MyManager(BaseManager.from_queryset(MyQuerySet)):
    pass
class MyModel(models.Model):
    objects = MyManager()
def callback_func(instance):
    instance.last_values_dict = json.loads(instance.last_valid_field_values)
    
    
MyModel.objects.all().apply_some_function_to_monkey_patch(callback_func)