Reputation: 68466
I am using Django 3.2.
I have a model like this:
class MyModel(models.Model):
last_valid_field_values = models.TextField(help_text='JSON field of fieldnames and values')
# ...
I want to be able to monkey patch my queries, so that when fetching MyModel
instances, I can added an attribute last_values_dict
— which is just the loaded JSON of the last_valid_field_values
.
So I would have something like this (pseudocode):
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)
How can I do this? I also think that possibly, this could be done via a generator iterating over the QuerySet
?
Upvotes: 2
Views: 266
Reputation: 43088
You can subclass QuerySet
to implement apply_some_function_to_monkey_patch
and override _fetch_all
to run the callback function, similar to how QuerySet.prefetch_related
is implemented. You also need to override __init__
and _clone
for it to work with filters.
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()
Usage:
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)
Upvotes: 1