In a django view, I need to append string data to the end of an existing text column in my database. So, for example, say I have a table named \"ATable\", and it has a fiel
seems you can't do this. however, what you are trying to do could be solved using transactions
(looks like you are using postgres, so if you want to do it in one query and use raw sql as suggested, ||
is the concatenation operator you want)
You can override F
object in Django with one simple change:
class CF(F):
ADD = '||'
Then just use CF
in place of F
. It will place "||" instead of "+" when generating SQL. For example, the query:
User.objects.filter(pk=100).update(email=CF('username') + '@gmail.com')
will generate the SQL:
UPDATE "auth_user" SET "email" = "auth_user"."username" || '@gmail.com'
WHERE "auth_user"."id" = 100
You can use the Concat db function.
from django.db.models import Value
from django.db.models.functions import Concat
ATable.objects.filter(id=100).update(some_field=Concat('some_field', Value('more string')))
In my case, I am adding a suffix for facebook avatars URIs like this:
FACEBOOK_URI = 'graph.facebook.com'
FACEBOOK_LARGE = '?type=large'
# ...
users = User.objects.filter(Q(avatar_uri__icontains=FACEBOOK_URI) & ~Q(avatar_uri__icontains=FACEBOOK_LARGE))
users.update(avatar_uri=Concat('avatar_uri', Value(FACEBOOK_LARGE)))
and I get SQL like this (Django 1.9):
UPDATE `user_user` SET `avatar_uri` = CONCAT(COALESCE(`user_user`.`avatar_uri`, ''), COALESCE('?type=large', ''))
WHERE (`user_user`.`avatar_uri` LIKE '%graph.facebook.com%' AND NOT (`user_user`.`avatar_uri` LIKE '%?type=large%' AND `user_user`.`avatar_uri` IS NOT NULL))
The result is all image URIs were changed from http://graph.facebook.com/<fb user id>/picture
to http://graph.facebook.com/<fb user id>/picture?type=large
And if you get this running, it isn't thread safe. While your update is running, some other process can update a model not knowing the data in the database is updated.
You have too acquire a lock, but don't forget this senario:
Now the field update became undone by the model instance in Django (Ghost write)
You can achieve this functionality with Django's select_for_update() operator: https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-for-update
Something like this:
obj = ATable.objects.select_for_update().get(id=100)
obj.aField = obj.aField + aStringVar
obj.save()
The table row will be locked when you call .select_for_update().get(), and the lock will be released when you call .save(), allowing you to perform the operation atomically.