4 ms·
INSERT or UPDATE in django's save() method
- cfinke 17y agoI 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 17y agoBut 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!
- almost 17y agoThis 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)
- mdasen 17y agohttp://code.djangoproject.com/ticket/9841 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 17y agoWhy 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
- DrJokepu 17y agoWhy 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)