New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pickle fails with models using FieldTracker #83
Comments
Verified with a dirt simple test in a21b9cc |
Unfortunatelly, my only solution was not pickling it in given scenario. |
The code in question, I believe, could be replaced by a signal. Working on a patch now. |
References jazzband#83. Instead of patching the save method of a tracked model class, we can use a signal handler on post_save, which means we can still pickle our model class. Note we can't just listen for the signal from the class we have, but instead listen for all post_save signals. This means we actually install a new signal handler for each tracked model class, which fires on all model save occurrences (and returns immediately if this handler doesn't care). We probably could improve this to have a registry of tracked models, or something, that allows us to just install one signal handler, and filter according to membership.
So, this passes all tests (including an equivalent one for kezzabelle's test above). However, I'm not 100% happy with it, as it installs a new signal handler for each tracked model, which listens to all models' post_save, and just exits early if it's not a subclass of the tracked model. Which may be acceptable, I'm not sure. |
Fixed by gh-130. |
I think this one can be closed now, @treyhunner. |
Just stumbled on this issue... would love to see a solution. ;) |
Same here as @bforchhammer |
Seems like custom User models are ubiquitous enough that this issue is blocking for many django projects. Django's locmem cache uses pickling, so I can't pickle functions that return User querysets or specific User instances. |
As a workaround, I used dill (https://github.com/uqfoundation/dill) instead of pickle in my code (for storing a queryset into cache). |
Unable pickle model with FieldTracker: tests/market/test_models.py:209: in test_market_offer_model_can_pickle
pickle.dumps(self.market_offer)
/usr/lib/python2.7/pickle.py:1374: in dumps
Pickler(file, protocol).dump(obj)
/usr/lib/python2.7/pickle.py:224: in dump
self.save(obj)
/usr/lib/python2.7/pickle.py:331: in save
self.save_reduce(obj=obj, *rv)
/usr/lib/python2.7/pickle.py:419: in save_reduce
save(state)
/usr/lib/python2.7/pickle.py:286: in save
f(self, obj) # Call unbound method with explicit self
/usr/lib/python2.7/pickle.py:649: in save_dict
self._batch_setitems(obj.iteritems())
/usr/lib/python2.7/pickle.py:663: in _batch_setitems
save(v)
/usr/lib/python2.7/pickle.py:286: in save
f(self, obj) # Call unbound method with explicit self
/usr/lib/python2.7/pickle.py:748: in save_global
(obj, module, name))
E PicklingError: Can't pickle <function save at 0x7f9a0d358230>: it's not found as model_utils.tracker.save |
I have following which allows me to pickle while preserving post-save signal functionality. `
` I just feel it is hackish to play around with signals execution order, so have not created PR it. If this seems fine, I will create PR for it. |
@csimple: In your solution, behavior of the field tracker in a save method is a little different than before. Currently, if you write: class Foo(models.Model):
bar = models.CharField(_('bar'), max_length=64)
field_tracker = FieldTracker(fields=['bar'])
def save(self, *args, **kwargs):
print(1, self.field_tracker.has_changed('bar'))
super().save(*args, **kwargs)
print(2, self.field_tracker.has_changed('bar'))
obj = Foo.objects.create(bar='bar')
obj.bar = 'new_bar'
obj.save() You will get: 1 True
2 True But if you run it using PickleFieldTracker proposed by @csimple, you will get: 1 True
2 False I am wondering which behavior is the correct one. |
@nomarek Since post save signals also return True (it returns True for both original as well as my solution), I think original behaviour was correct. Which means my earlier assumption that this could be fixed by patching signal is not correct, and we are back to square one. |
Guys, I was so happy when found this repo, apparently, as much as I got disappointed when I discovered this bug. |
I also would very much benefit from being able to add an object which has a field_tracker field to my redis cache! Can't do it without being able to pickle it |
+1 |
Since 3.2.0 |
This happens with custom User model in Django 1.5 (not sure if it matters). Haven't had a chance to try it with earlier versions or 1.6.
The text was updated successfully, but these errors were encountered: