Ticket #16649: save_inherit.diff

File save_inherit.diff, 3.1 KB (added by akaariai, 4 years ago)

Optimization for inherited model insertion, now the correct version

  • django/db/models/base.py

    diff --git a/django/db/models/base.py b/django/db/models/base.py
    index 2e6bea8..db25494 100644
    a b from django.utils.functional import curry 
    2424from django.utils.encoding import smart_str, force_unicode
    2525from django.utils.text import get_text_list, capfirst
    2626
     27UPDATED, INSERTED = 'UPDATED', 'INSERTED'
    2728
    2829class ModelBase(type):
    2930    """
    class Model(object): 
    473474        override this method. It's separate from save() in order to hide the
    474475        need for overrides of save() to pass around internal-only parameters
    475476        ('raw', 'cls', and 'origin').
     477
     478        Returns the action taken, which can be UPDATED or INSERTED. This is the
     479        action taken for the current model. It is possible that parent model
     480        was updated while current model is inserted. If the return value is
     481        UPDATED, then every model in the base chain was updated.
    476482        """
    477483        using = using or router.db_for_write(self.__class__, instance=self)
    478484        connection = connections[using]
    class Model(object): 
    494500        # attributes we have been given to the class we have been given.
    495501        # We also go through this process to defer the save of proxy objects
    496502        # to their actual underlying model.
     503        parent_action = None
    497504        if not raw or meta.proxy:
    498505            if meta.proxy:
    499506                org = cls
    class Model(object): 
    506513                if field and getattr(self, parent._meta.pk.attname) is None and getattr(self, field.attname) is not None:
    507514                    setattr(self, parent._meta.pk.attname, getattr(self, field.attname))
    508515
    509                 self.save_base(cls=parent, origin=org, using=using)
     516                parent_action = self.save_base(cls=parent, origin=org, using=using)
    510517
    511518                if field:
    512519                    setattr(self, field.attname, self._get_pk_val(parent._meta))
    513520            if meta.proxy:
    514                 return
     521                return parent_action
     522        # A small optimization: if parent was inserted, we know this model must be inserted, too.
     523        if parent_action == INSERTED:
     524            force_insert = True
    515525
    516526        if not meta.proxy:
    517527            non_pks = [f for f in meta.local_fields if not f.primary_key]
    class Model(object): 
    546556                       
    547557                elif not non_pks:
    548558                    # There are no other fields than the pk in the model. In this case we do
    549                     # not check the existense by update
     559                    # not check the existense by update.
    550560                    if manager.using(using).filter(pk=pk_val).exists():
    551561                        record_exists = True
    552562            if not pk_set or not record_exists:
    class Model(object): 
    590600            signals.post_save.send(sender=origin, instance=self,
    591601                created=(not record_exists), raw=raw, using=using)
    592602
     603        if meta.proxy:
     604            return parent_action
     605        if record_exists:
     606            return UPDATED
     607        else:
     608            return INSERTED
    593609
    594610    save_base.alters_data = True
    595611
Back to Top