I have Person
model as shown below:
# "store/models.py"
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=30)
<CASE 1>
Then, when I use select_for_update() and update() of a queryset together as shown below (I use Django 3.2.16):
# "store/views.py"
from django.db import transaction
from .models import Person
from django.http import HttpResponse
@transaction.atomic
def test(request):
# Here # Here
print(Person.objects.select_for_update().update(name="Tom"))
# Here # Here
print(Person.objects.select_for_update().all().update(name="Tom"))
# Here # Here
print(Person.objects.select_for_update().filter(id=1).update(name="Tom"))
return HttpResponse("Test")
Only UPDATE
query is run without SELECT FOR UPDATE
query as shown below. *I use PostgreSQL and these logs below are the queries of PostgreSQL and you can check on PostgreSQL, how to log queries with transaction queries such as "BEGIN" and "COMMIT":
But, when I use select_for_update()
and update()
of a queryset separately then put print(qs)
between them as shown below:
# "store/views.py"
from django.db import transaction
from .models import Person
from django.http import HttpResponse
@transaction.atomic
def test(request):
qs = Person.objects.select_for_update()
print(qs) # Here
qs.update(name="Tom")
qs = Person.objects.select_for_update().all()
print(qs) # Here
qs.update(name="Tom")
qs = Person.objects.select_for_update().filter(id=1)
print(qs) # Here
qs.update(name="Tom")
return HttpResponse("Test")
SELECT FOR UPDATE
and UPDATE
queries are run as shown below:
In addition, when I use select_for_update()
and save() of an object separately as shown below:
# "store/views.py"
from django.db import transaction
from .models import Person
from django.http import HttpResponse
@transaction.atomic
def test(request):
# Here
person1 = Person.objects.select_for_update().first()
person1.name = "Tom"
person1.save() # Here
# Here
person2 = Person.objects.select_for_update().all().first()
person2.name = "Tom"
person2.save() # Here
# Here
person3 = Person.objects.select_for_update().filter(id=1).first()
person3.name = "Tom"
person3.save() # Here
# Here
person4 = Person.objects.select_for_update().get(id=1)
person4.name = "Tom"
person4.save() # Here
return HttpResponse("Test")
SELECT FOR UPDATE
and UPDATE
queries are run as shown below:
<CASE 2>
And, when I use select_for_update()
and delete() of a queryset together as shown below:
# "store/views.py"
from django.db import transaction
from .models import Person
from django.http import HttpResponse
@transaction.atomic
def test(request):
# Here # Here
print(Person.objects.select_for_update().delete())
# Here # Here
print(Person.objects.select_for_update().all().delete())
# Here # Here
print(Person.objects.select_for_update().filter(id=1).delete())
return HttpResponse("Test")
Only DELETE
query is run without SELECT FOR UPDATE
query as shown below.
But, when I use select_for_update()
and delete()
of a queryset separately then put print(qs)
between them as shown below:
# "store/views.py"
from django.db import transaction
from .models import Person
from django.http import HttpResponse
@transaction.atomic
def test(request):
qs = Person.objects.select_for_update()
print(qs) # Here
qs.delete()
qs = Person.objects.select_for_update().all()
print(qs) # Here
qs.delete()
qs = Person.objects.select_for_update().filter(id=1)
print(qs) # Here
qs.delete()
return HttpResponse("Test")
SELECT FOR UPDATE
and DELETE
queries are run as shown below:
In addition, when I use select_for_update()
and delete()
of an object together as shown below:
# "store/views.py"
from django.db import transaction
from .models import Person
from django.http import HttpResponse
@transaction.atomic
def test(request):
# Here # Here
print(Person.objects.select_for_update().first().delete())
# Or
# Here # Here
print(Person.objects.select_for_update().all().first().delete())
# Or
# Here # Here
print(Person.objects.select_for_update().filter(id=1).first().delete())
# Or
# Here # Here
print(Person.objects.select_for_update().get(id=1).delete())
return HttpResponse("Test")
SELECT FOR UPDATE
and DELETE
queries are run as shown below:
I know QuerySets are lazy and When QuerySets are evaluated.
So, are there any other cases which select_for_update()
doesn't work but works with print(qs)
in Django in addition to what I've shown above?
Yes, there is other case which
select_for_update()
doesn't work but works withprint(qs)
in Django.For example, when I use
select_for_update()
and count() of a queryset together as shown below:SELECT
query is run instead ofSELECT FOR UPDATE
query as shown below:But, when I use
select_for_update()
andcount()
of a queryset separately then putprint(qs)
between them as shown below:SELECT FOR UPDATE
andSELECT
queries are run as shown below but there are two queriesSELECT FOR UPDATE
andSELECT
instead of one single querySELECT FOR UPDATE
:So to run one single query
SELECT FOR UPDATE
with the same result, I useselect_for_update()
and len() together which is a built-in function in Python as shown below:Then, one single query
SELECT FOR UPDATE
is run as shown below: