Django: Calling .update() on a single model instance retrieved by .get()?
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 thedefaults
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
How to select a record and update it, with a single queryset in Django?
Use the queryset object update
method:
MyModel.objects.filter(pk=some_value).update(field1='some value')
Run a django update but call the save method
The best way to do this is to just call save()
directly. You will need to call get()
instead of filter()
, though.
Asset.objects.get(pk=asset.pk).save(update_fields=item)
This isn't a problem since your existing filter()
is guaranteed to return a queryset with at most one Asset
anyway. You just have to be sure that the given pk
actually exists or wrap the get()
call in a try...except
block.
But...since you already have the Asset
instance in asset
, there's no reason to waste time with a DB query. Just call save
directly on the object you have:
asset.save(update_fields=item)
Django updating a single model
I would recommend updating the proper way using the save method. Maybe you can move you code from pre-save to post-save and check for the created flag. Or overload the save method and do what you have to do there. Another idea would be doing something like this:
User.objects.filter(pk=1)[0:1].update()
This slicing syntax returns a QuerySet upon which you can call your update method. You could call it without even without slicing, but then you yould theoretically update more than just your one model by mistake. Unless you filter by a primary key or something unique, that is.
Overloading the save method:
class MyModel(models.Model):
def save(self, some_value, *args, **kwargs):
# do your pre-save stuff here
super(MyModel, self).save(*args, **kwargs)
If need be you could even return from the save method or throw an excepption before calling the original save method. Then the model would not save. I don't think it is possible to do something like passing parameters from the save method to the signals. You can, however, pass additional parameters to the save method and then ommit them when calling the super method (I updated the example).
How to avoid retrieving instance to update field in Django
You can do this using F expressions. You can use this with queries and with (or without) update
and everything will take place at the SQL level.
Example from the docs:
from django.db.models import F
reporter = Reporters.objects.filter(name='Tintin')
reporter.update(stories_filed=F('stories_filed') + 1)
Django update only blank rows in model instance
Find one column which is always present, which also can be considered as unique on database (consider LogicalKey column).
for entry in entries:
try:
record = Model.objects.get(logical_key = entry['logical_key')
for k,v in entry.items():
if record._meta.get_field(k) is None:
setattr(record,k,v)
record.save()
except:
Model.objects.create(field1=entry['field1'],...)
How to update multiple fields of a django model instance?
It's tempting to mess with __dict__
, but that won't apply to attributes inherited from a parent class.
You can either iterate over the dict to assign to the object:
for (key, value) in my_data_dict.items():
setattr(obj, key, value)
obj.save()
Or you can directly modify it from a queryset (making sure your query set only returns the object you're interested in):
FooModel.objects.filter(whatever="anything").update(**my_data_dict)
Django: save() vs update() to update the database?
There are several key differences.
update
is used on a queryset, so it is possible to update multiple objects at once.
As @FallenAngel pointed out, there are differences in how custom save()
method triggers, but it is also important to keep in mind signals
and ModelManagers
. I have build a small testing app to show some valuable differencies. I am using Python 2.7.5, Django==1.7.7 and SQLite, note that the final SQLs may vary on different versions of Django and different database engines.
Ok, here's the example code.
models.py
:
from __future__ import print_function
from django.db import models
from django.db.models import signals
from django.db.models.signals import pre_save, post_save
from django.dispatch import receiver
__author__ = 'sobolevn'
class CustomManager(models.Manager):
def get_queryset(self):
super_query = super(models.Manager, self).get_queryset()
print('Manager is called', super_query)
return super_query
class ExtraObject(models.Model):
name = models.CharField(max_length=30)
def __unicode__(self):
return self.name
class TestModel(models.Model):
name = models.CharField(max_length=30)
key = models.ForeignKey('ExtraObject')
many = models.ManyToManyField('ExtraObject', related_name='extras')
objects = CustomManager()
def save(self, *args, **kwargs):
print('save() is called.')
super(TestModel, self).save(*args, **kwargs)
def __unicode__(self):
# Never do such things (access by foreing key) in real life,
# because it hits the database.
return u'{} {} {}'.format(self.name, self.key.name, self.many.count())
@receiver(pre_save, sender=TestModel)
@receiver(post_save, sender=TestModel)
def reicever(*args, **kwargs):
print('signal dispatched')
views.py
:
def index(request):
if request and request.method == 'GET':
from models import ExtraObject, TestModel
# Create exmple data if table is empty:
if TestModel.objects.count() == 0:
for i in range(15):
extra = ExtraObject.objects.create(name=str(i))
test = TestModel.objects.create(key=extra, name='test_%d' % i)
test.many.add(test)
print test
to_edit = TestModel.objects.get(id=1)
to_edit.name = 'edited_test'
to_edit.key = ExtraObject.objects.create(name='new_for')
to_edit.save()
new_key = ExtraObject.objects.create(name='new_for_update')
to_update = TestModel.objects.filter(id=2).update(name='updated_name', key=new_key)
# return any kind of HttpResponse
That resuled in these SQL queries:
# to_edit = TestModel.objects.get(id=1):
QUERY = u'SELECT "main_testmodel"."id", "main_testmodel"."name", "main_testmodel"."key_id"
FROM "main_testmodel"
WHERE "main_testmodel"."id" = %s LIMIT 21'
- PARAMS = (u'1',)
# to_edit.save():
QUERY = u'UPDATE "main_testmodel" SET "name" = %s, "key_id" = %s
WHERE "main_testmodel"."id" = %s'
- PARAMS = (u"'edited_test'", u'2', u'1')
# to_update = TestModel.objects.filter(id=2).update(name='updated_name', key=new_key):
QUERY = u'UPDATE "main_testmodel" SET "name" = %s, "key_id" = %s
WHERE "main_testmodel"."id" = %s'
- PARAMS = (u"'updated_name'", u'3', u'2')
We have just one query for update()
and two for save()
.
Next, lets talk about overriding save()
method. It is called only once for save()
method obviously. It is worth mentioning, that .objects.create()
also calls save()
method.
But update()
does not call save()
on models. And if no save()
method is called for update()
, so the signals are not triggered either. Output:
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
# TestModel.objects.get(id=1):
Manager is called [<TestModel: edited_test new_for 0>]
Manager is called [<TestModel: edited_test new_for 0>]
save() is called.
signal dispatched
signal dispatched
# to_update = TestModel.objects.filter(id=2).update(name='updated_name', key=new_key):
Manager is called [<TestModel: edited_test new_for 0>]
As you can see save()
triggers Manager
's get_queryset()
twice. When update()
only once.
Resolution. If you need to "silently" update your values, without save()
been called - use update
. Usecases: last_seen
user's field. When you need to update your model properly use save()
.
Related Topics
Windowserror: [Error 193] %1 Is Not a Valid Win32 Application in Python
Pythonic Way to Find Maximum Value and Its Index in a List
Using Tkinter in Python to Edit the Title Bar
Get Business Days Between Start and End Date Using Pandas
Python - Returning Nan When Trying to Predict With Keras
Running Command With Paramiko Exec_Command Causes Process to Sleep Before Finishing
Count Number of Empty Array Occurrences Within a 2D Array
Split Large Text File(Around 50Gb) into Multiple Files
How to Change Milliseconds to Seconds in Python
How to Print Specific Key Value from a Dictionary
Jupyter Notebook, Python3 Print Function: No Output, No Error
Print the Lines of a Log File Which Starts With Date Format "Yyyy-Mm-Dd" in Python
How to Easily Print Ascii-Art Text
Fbprophet Installation Error - Failed Building Wheel for Fbprophet
Typeerror: Unsupported Format String Passed to List._Format_
Pandas: Difference Between Pivot and Pivot_Table. Why Is Only Pivot_Table Working