When saving, how can you check if a field has changed?

前端 未结 25 1713
鱼传尺愫
鱼传尺愫 2020-11-22 07:15

In my model I have :

class Alias(MyBaseModel):
    remote_image = models.URLField(max_length=500, null=True, help_text=\"A URL that is downloaded and cached          


        
相关标签:
25条回答
  • 2020-11-22 07:18

    As of Django 1.8, there's the from_db method, as Serge mentions. In fact, the Django docs include this specific use case as an example:

    https://docs.djangoproject.com/en/dev/ref/models/instances/#customizing-model-loading

    Below is an example showing how to record the initial values of fields that are loaded from the database

    0 讨论(0)
  • 2020-11-22 07:18

    Very late to the game, but this is a version of Chris Pratt's answer that protects against race conditions while sacrificing performance, by using a transaction block and select_for_update()

    @receiver(pre_save, sender=MyModel)
    @transaction.atomic
    def do_something_if_changed(sender, instance, **kwargs):
        try:
            obj = sender.objects.select_for_update().get(pk=instance.pk)
        except sender.DoesNotExist:
            pass # Object is new, so field hasn't technically changed, but you may want to do something else here.
        else:
            if not obj.some_field == instance.some_field: # Field has changed
                # do something
    
    0 讨论(0)
  • 2020-11-22 07:19

    And now for direct answer: one way to check if the value for the field has changed is to fetch original data from database before saving instance. Consider this example:

    class MyModel(models.Model):
        f1 = models.CharField(max_length=1)
    
        def save(self, *args, **kw):
            if self.pk is not None:
                orig = MyModel.objects.get(pk=self.pk)
                if orig.f1 != self.f1:
                    print 'f1 changed'
            super(MyModel, self).save(*args, **kw)
    

    The same thing applies when working with a form. You can detect it at the clean or save method of a ModelForm:

    class MyModelForm(forms.ModelForm):
    
        def clean(self):
            cleaned_data = super(ProjectForm, self).clean()
            #if self.has_changed():  # new instance or existing updated (form has data to save)
            if self.instance.pk is not None:  # new instance only
                if self.instance.f1 != cleaned_data['f1']:
                    print 'f1 changed'
            return cleaned_data
    
        class Meta:
            model = MyModel
            exclude = []
    
    0 讨论(0)
  • 2020-11-22 07:21

    If you are using a form, you can use Form's changed_data (docs):

    class AliasForm(ModelForm):
    
        def save(self, commit=True):
            if 'remote_image' in self.changed_data:
                # do things
                remote_image = self.cleaned_data['remote_image']
                do_things(remote_image)
            super(AliasForm, self).save(commit)
    
        class Meta:
            model = Alias
    
    0 讨论(0)
  • 2020-11-22 07:22

    Here is another way of doing it.

    class Parameter(models.Model):
    
        def __init__(self, *args, **kwargs):
            super(Parameter, self).__init__(*args, **kwargs)
            self.__original_value = self.value
    
        def clean(self,*args,**kwargs):
            if self.__original_value == self.value:
                print("igual")
            else:
                print("distinto")
    
        def save(self,*args,**kwargs):
            self.full_clean()
            return super(Parameter, self).save(*args, **kwargs)
            self.__original_value = self.value
    
        key = models.CharField(max_length=24, db_index=True, unique=True)
        value = models.CharField(max_length=128)
    

    As per documentation: validating objects

    "The second step full_clean() performs is to call Model.clean(). This method should be overridden to perform custom validation on your model. This method should be used to provide custom model validation, and to modify attributes on your model if desired. For instance, you could use it to automatically provide a value for a field, or to do validation that requires access to more than a single field:"

    0 讨论(0)
  • 2020-11-22 07:23

    as an extension of SmileyChris' answer, you can add a datetime field to the model for last_updated, and set some sort of limit for the max age you'll let it get to before checking for a change

    0 讨论(0)
提交回复
热议问题