skip_hooks context manager
Opened this issue · 1 comments
Due to the current way skip_hooks works, you need to pass it into save(), you can not suppress hooks in the case of using model.objects.get_or_create
. You can't just pass in skip_hooks
to that method as it's used when initing the new model, and in inital get request.
For create() it would be possible to eaisly fix by popping out skip_hooks from init's kwags
def create(self, **kwargs):
"""
Create a new object with the given kwargs, saving it to the database
and returning the created object.
"""
obj = self.model(**kwargs)
self._for_write = True
obj.save(force_insert=True, using=self.db)
return obj
class LifecycleModelMixin(object):
def __init__(self, *args, **kwargs):
self._skip_hooks = kwargs.pop("skip_hooks", None) #newline
super().__init__(*args, **kwargs)
self._initial_state = self._snapshot_state()
and then in save also check the non_null sate of self._get_hooks
@transaction.atomic
def save(self, *args, **kwargs):
skip_hooks = kwargs.pop("skip_hooks", False) or self._skip_hooks
But that doesn't fix that skip_hooks=True
will be passed to the queryset filter.
So in that case, the only solution would be some global var/instance which is set using enter and exit
class SkipHooks() :
skip_hooks = False
def __enter__(self):
self.skip_hooks = True
def __exit__(self):
self.skip_hooks = False
skip_hooks = SkipHooks()
with skip_hooks:
foo.save()
@transaction.atomic
def save(self, *args, **kwargs):
skip_hooks = kwargs.pop("skip_hooks", False) or self._skip_hooks or skip_hooks.skip_hooks
Does anyone have any comments on this?
And if I were to make the proposed changes, would they PR be accepted?
Thanks for this suggestion!
I like the context manager approach, I've seen similar patterns in other projects like django-modeltranslation
:
If you want to provide an implementation for this let me know, if not when I have some spare time I could try to do it.