71

I want to run a django update through the ORM that looks something like this:

MyModel.objects.filter(**kwargs).update(my_field=F('my_other_field')+'a string')

This causes MySQL to throw an exception. Is there anyway to do this without writing raw SQL?

Zach
  • 18,594
  • 18
  • 59
  • 68
  • I think what you need is described here https://stackoverflow.com/questions/8143362/django-using-an-f-expression-for-a-text-field-in-an-update-call/25077907#25077907 – Martin Faucheux Sep 22 '20 at 01:50

3 Answers3

157

I had a similar issue; basically I wanted to concatenate two fields to the get the full name of a user. I got it solved this way(but must say that I was using Postgres):

from django.db.models.functions import Concat
from django.db.models import F, Value, CharField

AnyModel.objects.filter(**kwargs).annotate(full_name=Concat(F('model__user_first_name'), Value(' '), F('model__user_last_name'), output_field=CharField()))

where, F('...') evaluates its argument as a query, so you can query a field of the model itself, or span across models as you would do in filter/get, while Value('...') evaluates its argument literally(in my case I needed a space to be placed in between first_name and last_name), and output_field=... specifies the Type of the annotated field(I wanted to be a CharField). For more info, you can read Django docs about Concat

starball
  • 20,030
  • 7
  • 43
  • 238
tombishop83
  • 1,837
  • 2
  • 12
  • 12
45

What's happening is that Django is passing the '+' through to SQL - but SQL doesn't allow the use of '+' for concatenation, so it tries to add numerically. If you use an integer in place of 'a string', it does work in the sense that it adds the integer value of my_other_field to your variable.

It's debatable whether this is a bug. The documentation for F() objects in lookup queries states:

Django supports the use of addition, subtraction, multiplication, division and modulo arithmetic with F() objects

so it could be argued that you shouldn't be trying to use it to update with strings. But that's certainly not documented, and the error message 'Incorrect DOUBLE value' is not very helpful. I'll open a ticket.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • 1
    In SQLite it's even less helpful: it just sets the text to "0"! – boxed Feb 05 '15 at 13:15
  • 1
    This is a great answer but it doesn't answer the question. Is using `Concat` and `Value` the best way to achieve what is asked? – Cyrlop Aug 22 '18 at 15:25
42

You can use Concat function https://docs.djangoproject.com/en/1.9/ref/models/database-functions/#concat

from django.db.models.functions import Concat
from django.db.models import Value

MyModel.objects.filter(**kwargs).update(my_field=Concat('my_other_field', Value('a string'))
Alexey Ruzin
  • 967
  • 8
  • 17