#27335: Avoid object save during QuerySet.update_or_create when there were no
changes
----------------------------------------------+--------------------
     Reporter:  tonnzor                       |      Owner:  nobody
         Type:  Cleanup/optimization          |     Status:  new
    Component:  Database layer (models, ORM)  |    Version:  master
     Severity:  Normal                        |   Keywords:
 Triage Stage:  Unreviewed                    |  Has patch:  0
Easy pickings:  0                             |      UI/UX:  0
----------------------------------------------+--------------------
 Right now when you use QuerySet.update_or_create -- it always saves into
 DB even if there were no changes.

 It would be great that if nothing is changed -- nothing is saved into DB.
 I found myself often reusing the same pattern in our projects.

 Use case:

 {{{#!python
 >>> from django.contrib.auth.models import User
 >>> User.objects.create(is_superuser=True, username='admin',
 is_active=True) # generate a use in DB to work with
 >>> # later in our code
 >>> user, created = User.objects.update_or_create(defaults={'is_active':
 True}, username='admin')
 # here an extra DB write though no data were changed
 }}}

 If you check the current code in master
 (https://github.com/django/django/blob/master/django/db/models/query.py#L477):
 {{{#!python
             try:
                 obj = self.select_for_update().get(**lookup)
             except self.model.DoesNotExist:
                 obj, created = self._create_object_from_params(lookup,
 params)
                 if created:
                     return obj, created
             for k, v in six.iteritems(defaults):
                 setattr(obj, k, v() if callable(v) else v)
             obj.save(using=self.db) # HERE IT IS => always save
 }}}

 If object exists in DB, it would apply all attributes from `default` and
 save it even if there were no changes in values.

 We could do something like that:
 {{{#!python
             changed = False
             for k, v in six.iteritems(defaults):
                 v = v() if callable(v) else v
                 if v != getattr(obj, k):
                     modified = True
                     setattr(obj, k, v)
             if changed:
                 obj.save(using=self.db) # save only if there were changes
 }}}

 If you think it is too complex for all use cases, we may put a flag for
 enabling / disabling this feature or have another method for this logic.

--
Ticket URL: <https://code.djangoproject.com/ticket/27335>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/050.4e2e256a5cdeb082cf9ea4ebfa1f9af2%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to