How to exclude django model fields during save?

I have a rather complex Django model that includes some fields that should only be saved under certain circumstances. As a simple example,

from django.db import models

class MyModel(models.Model):
    name = models.CharField(max_length=200)
    counter = models.IntegerField(default=0)

    def increment_counter(self):
        self.counter = models.F('counter') + 1
        self.save(update_fields=['counter'])

Here I use the expressions F to avoid race conditions when increasing the counter. Usually I don’t want to store the counter value outside the function increment_counter, as this could potentially cancel the increment called from another thread or process.

So the question is, what is the best way to exclude certain default fields in the model save function? I tried the following

def save(self, **kwargs):
    if update_fields not in kwargs:
        update_fields = set(self._meta.get_all_field_names())
        update_fields.difference_update({
            'counter',
        })
        kwargs['update_fields'] = tuple(update_fields)
    super().save(**kwargs)

ValueError: The following fields do not exist in this model or are m2m fields: id. , , id m2m , , , self._meta.get_all_field_names(), update_fields.

, django; model_obj.save() update_fields.

+4
1

:

from django.db import models

class MyModel(models.Model):
    name = models.CharField(max_length=200)
    counter = models.IntegerField(default=0)

    default_save_fields = None

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.default_save_fields is None:
            # This block should only get called for the first object loaded
            default_save_fields = {
                f.name for f in self._meta.get_fields()
                if f.concrete and not f.many_to_many and not f.auto_created
            }
            default_save_fields.difference_update({
                'counter',
            })
            self.__class__.default_save_fields = tuple(default_save_fields)

    def increment_counter(self):
        self.counter = models.F('counter') + 1
        self.save(update_fields=['counter'])    

    def save(self, **kwargs):
        if self.id is not None and 'update_fields' not in kwargs:
            # If self.id is None (meaning the object has yet to be saved)
            # then do a normal update with all fields.
            # Otherwise, make sure `update_fields` is in kwargs.
            kwargs['update_fields'] = self.default_save_fields
        super().save(**kwargs)

, , , ForeignKey, , .

0

Source: https://habr.com/ru/post/1612332/


All Articles