
INSERT or UPDATE in django's save() method - karol_zielinski
http://tech.karolzielinski.com/insert-or-update-in-djangos-save-method
======
cfinke
I find Django to be very inefficient in how it handles INSERT vs. UPDATE;
you're better off specifing force_insert or force_update in the call to save()
to avoid the extra SELECT it runs, since you almost always know whether the
object you're saving is new or should be updated.

~~~
almost
But only in the cases where it actually matters which given normal DB usage
patterns for most sites is often nowhere. No point in making things more
complicated when it's not needed!

------
DrJokepu
Why doesn't Django try to do an UPDATE using the non-NULL primary key and look
at the number of updated rows (which is returned by all the SQL databases I
know) and if it's zero only then do an INSERT? This way it would only have to
do two queries for inserts and still remain idiot-safe. An UPDATE using the
primary key that can't find any rows consumes the same amount of resources as
a SELECT.

(This approach would cause problems with funny black magic triggers but funny
black magic triggers cause problems anyway)

------
mdasen
<http://code.djangoproject.com/ticket/9841>

It's been reported before and they consciously chose the current behavior. I
don't agree with their decision, but it is something they're aware of.

EDIT: There is a way to subclass models.Model and not have it be an abstract
or real model (I don't remember at the moment) and you could, in that
subclass, do a force_insert or force_update based on the PK status so that
everything in your project inheriting from that subclass would have that
behavior.

basically:

    
    
      def save(self, *args, **kwargs):
          if self.pk:
              kwargs['force_update'] = True
              kwargs['force_insert'] = False
          else:
              kwargs['force_insert'] = True
              kwargs['force_update'] = False
          super(MyModelBase, self).save(*args, **kwargs)
    

So, one can modify that behavior if they want to without having to patch too
much - maybe someone can comment on subclassing models.Model while not having
Django consider it a model (I think I got it from the Pro Django book if
someone has it available).

EDIT2: modified the code to make sure that force_insert and force_update
couldn't both be True.

~~~
almost
Why wouldn't you just make the it an abstract base model without any fields?
If that's not what you want though you should be able to get that behavior
using multiple inheritance:

    
    
        class AlwaysUpdate(object):
          def save(self, *args, **kwargs):
              if self.pk:
                  kwargs['force_update'] = True
                  kwargs['force_insert'] = False
              else:
                  kwargs['force_insert'] = True
                  kwargs['force_update'] = False
              return super(AlwaysUpdate, self).save(*args, **kwargs)
    
        class MyModel(AlwaysUpdate, models.Model):
          pass # model def here

------
almost
This code will cause problems with some parts of Django. I forget where, but I
have encountered problems writing code like this before because sometimes the
save method gets called by things which expect it to take its optional
parameters. This is a more robust (although certainly uglier) version:

    
    
        def save(self, *args, **kwargs):
          if not self.pk:
            pass # new object
          else:
            pass # old object
          return super(MyObject, self).save(*args, **kwargs)

