98👍
For Django 1.11+ you can use Subquery:
from django.db.models import OuterRef, Subquery, Sum
Relation.objects.update(
rating=Subquery(
Relation.objects.filter(
id=OuterRef('id')
).annotate(
total_rating=Sum('sign_relations__rating')
).values('total_rating')[:1]
)
)
This code produce the same SQL code proposed by Tomasz Jakub Rup but with no use of RawSQL expression. The Django documentation warns against the use of RawSQL due to the possibility of SQL injection).
Update
I published an article based on this answer with more in-depth explanations: Updating a Django queryset with annotation and subquery on paulox.net
7👍
UPDATE
statement doesn’t support GROUP BY
. See e.g. PostgreSQL Docs, SQLite Docs.
You need someting like this:
UPDATE relation
SET rating = (SELECT SUM(rating)
FROM sign_relation
WHERE relation_id = relation.id)
Equivalent in DjangoORM:
from django.db.models.expressions import RawSQL
Relation.objects.all(). \
update(rating=RawSQL('SELECT SUM(rating) FROM signrelation WHERE relation_id = relation.id', []))
or:
from django.db.models import F, Sum
from django.db.models.expressions import RawSQL
Relation.objects.all(). \
update(rating=RawSQL(SignRelation.objects. \
extra(where=['relation_id = relation.id']). \
values('relation'). \
annotate(sum_rating=Sum('rating')). \
values('sum_rating').query, []))
- [Django]-Django: no such table: django_session
- [Django]-How to strip html/javascript from text input in django
- [Django]-Database returned an invalid value in QuerySet.dates()
-1👍
You can define your own custom objects manager:
class RelationManager(models.Manager):
def annotated(self,*args,*kwargs):
queryset = super(RelationManager,self).get_queryset()
for obj in queryset:
obj.rating = ... do something ...
return queryset
class Relations(models.Model):
rating = models.IntegerField(default=0)
rating_objects = RelationManager()
Then in your code:
q = Realation.rating_objects.annotated()
Add args/kwargs to customise what this manager returns.
- [Django]-How to access outermost forloop.counter with nested for loops in Django templates?
- [Django]-Best practices for getting the most testing coverage with Django/Python?
- [Django]-Django Framework – Is there a shutdown event that can be subscribed to?
-1👍
Workaround for postgres:
with connection.cursor() as cursor:
sql, params = qs.query.sql_with_params()
cursor.execute("""
WITH qs AS ({})
UPDATE foo SET bar = qs.bar
FROM qs WHERE qs.id = foo.id
""".format(sql), params)
- [Django]-How can I use the variables from "views.py" in JavasScript, "<script></script>" in a Django template?
- [Django]-Command not found: django-admin.py
- [Django]-Django – {% csrf_token %} was used in a template, but the context did not provide the value
-4👍
If you want to avoid many calls to the database, you should use transaction.atomic
.
Read more on Django documentation: https://docs.djangoproject.com/en/1.9/topics/db/transactions/#controlling-transactions-explicitly
- [Django]-WARNING Not Found: /favicon.ico in Django
- [Django]-Is there a filter for divide for Django Template?
- [Django]-HTTPError 403 (Forbidden) with Django and python-social-auth connecting to Google with OAuth2
-5👍
You really can’t do this. Take a look at the code for update
and follow it through for some fine reading.
Honestly, what’s wrong with placing something like this in a Manager definition? Put those 3 lines you don’t want to put in your view into a manager, call that manager as necessary. Additionally, you’re doing much less “magic” and when the next developer looks at your code, they won’t have to resort to a few WTF’s .. 🙂
Also, I was curious and it looks like you can use SQL Join with UPDATE statements but it’s some classic SQL hackery .. So if you’re so inclined, you can use Djangos raw SQL functionality for that 😉
- [Django]-List field in model?
- [Django]-How to display the current year in a Django template?
- [Django]-How do I migrate a model out of one django app and into a new one?