Code

Ticket #17340: insert-update-distinction.patch

File insert-update-distinction.patch, 2.5 KB (added by jonash, 3 years ago)
  • django/db/backends/__init__.py

    54c3191 INSERT/UPDATE distinction option
    diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
    index f627b54..abb45c7 100644
    a b class BaseDatabaseFeatures(object): 
    314314    has_select_for_update_nowait = False 
    315315 
    316316    supports_joins = True 
     317    distinguishes_insert_from_update = True 
    317318    supports_select_related = True 
    318319    supports_deleting_related_objects = True 
    319320 
  • django/db/models/base.py

    diff --git a/django/db/models/base.py b/django/db/models/base.py
    index ebd67be..39598ef 100644
    a b class Model(object): 
    366366                    pass 
    367367            if kwargs: 
    368368                raise TypeError("'%s' is an invalid keyword argument for this function" % kwargs.keys()[0]) 
     369        self._original_pk = self.pk if self._meta.pk is not None else None 
    369370        super(Model, self).__init__() 
    370371        signals.post_init.send(sender=self.__class__, instance=self) 
    371372 
    class Model(object): 
    474475        ('raw', 'cls', and 'origin'). 
    475476        """ 
    476477        using = using or router.db_for_write(self.__class__, instance=self) 
     478        entity_exists = not self._state.adding or self._original_pk == self.pk 
    477479        assert not (force_insert and force_update) 
    478480        if cls is None: 
    479481            cls = self.__class__ 
    class Model(object): 
    519521            pk_set = pk_val is not None 
    520522            record_exists = True 
    521523            manager = cls._base_manager 
    522             if pk_set: 
     524            # TODO/NONREL: Some backends could emulate force_insert/_update 
     525            # with an optimistic transaction, but since it's costly we should 
     526            # only do it when the user explicitly wants it. 
     527            # By adding support for an optimistic locking transaction 
     528            # in Django (SQL: SELECT ... FOR UPDATE) we could even make that 
     529            # part fully reusable on all backends (the current .exists() 
     530            # check below isn't really safe if you have lots of concurrent 
     531            # requests. BTW, and neither is QuerySet.get_or_create). 
     532            try_update = connections[using].features.distinguishes_insert_from_update 
     533            if not try_update: 
     534                record_exists = False 
     535 
     536            if try_update and pk_set: 
    523537                # Determine whether a record with the primary key already exists. 
    524538                if (force_update or (not force_insert and 
    525539                        manager.using(using).filter(pk=pk_val).exists())):