开发者

What is the best / proper idiom in django for modifying a field during a .save() where you need to old value?

开发者 https://www.devze.com 2022-12-27 17:20 出处:网络
say I\'ve got: class LogModel(models.Model): message = models.CharField(max_length=512) class Assignment(models.Model):

say I've got:

class LogModel(models.Model):
    message = models.CharField(max_length=512)

class Assignment(models.Model):
    someperson = models.ForeignKey(SomeOtherModel)
    def save(self, *args, **kwargs):
        super(Assignment, self).save()
        old_person = #?????
        LogModel(message="%s is no longer assigned to %s"%(old_person, self).save()
        LogModel(message="%s is now assigned to %s"%(self.someperson, self).save()

My goal is to save to LogModel some messages about who Assignment was assigned to. Notice that I need to know the old, presave value of this field.

I have seen code that suggests, before super().save(), retrieve the instance from the database via primary key and grab the old value from there. This could work, but is a bit me开发者_高级运维ssy.

In addition, I plan to eventually split this code out of the .save() method via signals - namely pre_save() and post_save(). Trying to use the above logic (Retrieve from the db in pre_save, make the log entry in post_save) seemingly fails here, as pre_save and post_save are two seperate methods. Perhaps in pre_save I can retrieve the old value and stick it on the model as an attribute?

I was wondering if there was a common idiom for this. Thanks.


A couple of months ago I found somewhere online a good way to do this...

class YourModel(models.Model):

    def __init__(self, *args, **kwargs):
        super(YourModel, self).__init__(*args, **kwargs)
        self.original = {}
        id = getattr(self, 'id', None)

        for field in self._meta.fields:
            if id:
                self.original[field.name] = getattr(self, field.name, None)
            else:
                self.original[field.name] = None

Basically a copy of the model fields will get saved to self.original. You can then access it elsewhere in the model...

def save(self, *args, **kwargs):
    if self.original['my_property'] != self.my_property:
        # ...


It can be easily done with signals. There are, respectively a pre-save and post-save signal for every Django Model.


So I came up with this:

class LogModel(models.Model):
    message = models.CharField(max_length=512)

class Assignment(models.Model):
    someperson = models.ForeignKey(SomeOtherModel)

import weakref
_save_magic = weakref.WeakKeyDictionary()

@connect(pre_save, Assignment)
def Assignment_presave(sender, instance, **kwargs):
    if instance.pk:
        _save_magic[instance] = Assignment.objects.get(pk=instance.pk).someperson

@connect(post_save, Assignment)
def Assignment_postsave(sender, instance, **kwargs):
    old = None
    if instance in _save_magic:
        old = _save_magic[instance]
        del _save_magic[instance]
        LogModel(message="%s is no longer assigned to %s"%(old, self).save()
    LogModel(message="%s is now assigned to %s"%(instance.someperson, self).save()

What does StackOverflow think? Anything better? Any tips?

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号