Django: Calling .update() on a single model instance retrieved by .get()?

175,608

Solution 1

With the advent of Django 1.7, there is now a new update_or_create QuerySet method, which should do exactly what you want. Just be careful of potential race conditions if uniqueness is not enforced at the database level.

Example from the documentation:

obj, created = Person.objects.update_or_create(
    first_name='John', last_name='Lennon',
    defaults={'first_name': 'Bob'},
)

The update_or_create method tries to fetch an object from database based on the given kwargs. If a match is found, it updates the fields passed in the defaults dictionary.


Pre-Django 1.7:

Change the model field values as appropriate, then call .save() to persist the changes:

try:
    obj = Model.objects.get(field=value)
    obj.field = new_value
    obj.save()
except Model.DoesNotExist:
    obj = Model.objects.create(field=new_value)
# do something else with obj if need be

Solution 2

if you want only to update model if exist (without create it):

Model.objects.filter(id = 223).update(field1 = 2)

mysql query:

UPDATE `model` SET `field1` = 2 WHERE `model`.`id` = 223

Solution 3

As of Django 1.5, there is an update_fields property on model save. eg:

obj.save(update_fields=['field1', 'field2', ...])

https://docs.djangoproject.com/en/dev/ref/models/instances/

I prefer this approach because it doesn't create an atomicity problem if you have multiple web app instances changing different parts of a model instance.

Solution 4

I don't know how good or bad this is, but you can try something like this:

try:
    obj = Model.objects.get(id=some_id)
except Model.DoesNotExist:
    obj = Model.objects.create()
obj.__dict__.update(your_fields_dict) 
obj.save()

Solution 5

Here's a mixin that you can mix into any model class which gives each instance an update method:

class UpdateMixin(object):
    def update(self, **kwargs):
        if self._state.adding:
            raise self.DoesNotExist
        for field, value in kwargs.items():
            setattr(self, field, value)
        self.save(update_fields=kwargs.keys())

The self._state.adding check checks to see if the model is saved to the database, and if not, raises an error.

(Note: This update method is for when you want to update a model and you know the instance is already saved to the database, directly answering the original question. The built-in update_or_create method featured in Platinum Azure's answer already covers the other use-case.)

You would use it like this (after mixing this into your user model):

user = request.user
user.update(favorite_food="ramen")

Besides having a nicer API, another advantage to this approach is that it calls the pre_save and post_save hooks, while still avoiding atomicity issues if another process is updating the same model.

Share:
175,608
zhuyxn
Author by

zhuyxn

Updated on November 16, 2021

Comments

  • zhuyxn
    zhuyxn over 2 years

    I have a function which currently calls Models.object.get(), which returns either 0 or 1 model objects. If it returns 0, I create a new model instance in the except DoesNotExist clause of the function. Otherwise, I would like to update the fields in the pre-existing instance, without creating a new one. I was originally attempting to call .update() on the instance which was found, but .update() seems to be only callable on a QuerySets. How do I get around changing a dozen fields, without calling .filter() and comparing the lengths to know if I have to create or update a pre-existing instance?