Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make a Django update with a conditional case?

Tags:

django

I would like to use Django to update a field to a different value depending on its current value, but I haven't figured out how to do it without doing 2 separate update statements.

Here's an example of what I'd like to do:

now = timezone.now()
data = MyData.objects.get(pk=dataID)
if data.targetTime < now:
    data.targetTime = now + timedelta(days=XX)
else:
    data.targetTime = data.targetTime + timedelta(days=XX)
data.save()

Now, I'd like to use an update() statement to avoid overwriting other fields on my data, but I don't know how to do it in a single update(). I tried some code like this, but the second update didn't use the up to date time (I ended up with a field equal to the current time) :

# Update the time to the current time
now = timezone.now()
MyData.objects.filter(pk=dataID).filter(targetTime__lt=now).update(targetTime=now)
# Then add the additional time
MyData.objects.filter(pk=dataID).update(targetTime=F('targetTime') + timedelta(days=XX))

Is there a way I can reduce this to a single update() statement? Something similar to the SQL CASE statement?

like image 271
camomilk Avatar asked Jun 17 '13 19:06

camomilk


People also ask

How Django knows to update VS insert?

The doc says: If the object's primary key attribute is set to a value that evaluates to True (i.e. a value other than None or the empty string), Django executes an UPDATE. If the object's primary key attribute is not set or if the UPDATE didn't update anything, Django executes an INSERT link.

What does .values do in Django?

values() Returns a QuerySet that returns dictionaries, rather than model instances, when used as an iterable. Each of those dictionaries represents an object, with the keys corresponding to the attribute names of model objects.

What is OuterRef Django?

to Django users. According to the documentation on models. OuterRef: It acts like an F expression except that the check to see if it refers to a valid field isn't made until the outer queryset is resolved.

What is Django's ORM?

From IDEA to Product Using Python / Django ORM stands for Object Relational Mapper. The main goal of ORM is to send data between a database and models in an application. It maps a relation between the database and a model. So, ORM maps object attributes to fields of a table.


1 Answers

You need to use conditional expressions, like this

from django.db.models import Case, When, F

object = MyData.objects.get(pk=dataID)
now = timezone.now()
object.targetTime = Case(
    When(targetTime__lt=now, then=now + timedelta(days=XX)),
    default=F('targetTime') + timedelta(days=XX)
)
object.save(update_fields=['targetTime'])

For debugging, try running this right after save to see what SQL queries have just run:

import pprint
from django.db import connection
pprint.pprint(["queries", connection.queries])

I've tested this with integers and it works in Django 1.8, I haven't tried dates yet so it might need some tweaking.

like image 108
Flimm Avatar answered Nov 13 '22 01:11

Flimm