简体   繁体   中英

Django - Override model save()

In our project we use soft delete (is_deleted attribute on a model). Before creating a new model I want to first check if it was already exist and deleted and if so - set is_deleted=False and save the already exists model. So I decided to override the model 'save' method. (not the View Create since it should work not only for requests) The problem is that 'save()' is called for all actions (create, update, delete). Is there a way I can call the overridden method only on create?

class Model(BaseModel):
    title = models.CharField(max_length=200)
    identifier = models.CharField(max_length=15)

    def save(self, *args, **kwargs):
        try:                                               
            existing_model = Model.objects.active_and_deleted().get(                                                        identifier=self.identifier)

            if self.is_deleted is False:
                existing_model.is_deleted = False
                existing_model.title = self.title
                existing_model.created_at = self.created_at
                existing_model.updated_at = self.updated_at
                existing_model.created_by = self.created_by
                existing_model.deleted_at = None
                super(Model, existing_model).save(args, kwargs)
        except Model.DoesNotExist:
            # in case the Nodel wasn't already exist - continue
            pass
        super(Model, self).save(*args, **kwargs)

The answer to your question, "Is there a way I can call the overridden method only on create?" is this:

    def save(self, *args, **kwargs):

        if not self.id:
            # Object is a new instance

        return super(Model, self).save(*args, **kwargs)

But there are other issues here. Your model shouldn't be named "Model", for example.

Check whether self.pk is None or not could do what you want, here is an example:

class ModelName(mdoels.Model):
    title = models.CharField(max_length=200)
    identifier = models.CharField(max_length=15)

    def save(self, *args, **kwargs):
        if self.pk is None:  # Adding of a new instance
            # let's say we compare instances by `title`
            # you can use other fields for the comparison
            possible_old_instance = Model.objects.filter(title__iexact=self.title)                                            
            if possible_old_instance.exists():
                existing_model = possible_old_instance.first()
                existing_model.is_deleted = False
                existing_model.title = self.title
                existing_model.created_at = self.created_at
                existing_model.updated_at = self.updated_at
                existing_model.created_by = self.created_by
                existing_model.deleted_at = None
                existing_model.save()
                # Nothing happens, we don't call save() method
            else:
                # in case the Model doesn't exist
                super(ModelName, self).save(*args, **kwargs)
        else:
            super(ModelName, self).save(*args, **kwargs)

In case when you are using the UUID field instead of the default ID field, check self.pk field is a terrible idea because UUID is assigned as default before we go to the save method. Well, how to resolve it? The simplest and fastest solution is self._state.adding instead of self.pk

I hope you noticed an underscore before the "state" word, but don't worry, this method is completely legal and we do not call here a private variable.

Example:

def save(self, *args, **kwargs):
    if self._state.adding: # will return true if obcject is newly created
            # Object is a new instance

        return super(Model, self).save(*args, **kwargs)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM