2010-09-06 16 views
16

Açıklamalı değer kullanarak queryset'deki tüm satırları güncellemek istiyorum. Django açıklama notuyla birlikte queryset

ben basit modelleri var:

class Relation(models.Model): 
    rating = models.IntegerField(default=0) 

class SignRelation(models.Model): 
    relation = models.ForeignKey(Relation, related_name='sign_relations') 
    rating = models.IntegerField(default=0) 

Ve bu kodu awoid istiyorum:

for relation in Relation.objects.annotate(total_rating=Sum('sign_relations__rating')): 
    relation.rating = relation.total_rating or 0 
    relation.save() 

Ve böyle bir şey kullanarak bir SQL istek yılında güncelleştirme yapın:

Relation.objects.update(rating=Sum('sign_relations__rating')) 

Çalışmıyor:

TypeError: int() argument must be a string or a number, not 'Sum' 

veya

Relation.objects.annotate(total_rating=Sum('sign_relations__rating')).update(rating=F('total_rating')) 

Ayrıca çalışmaz:

DatabaseError: missing FROM-clause entry for table "relations_signrelation" 
LINE 1: UPDATE "relations_relation" SET "rating" = SUM("relations_si... 

bu amaçla Django'nın ORM kullanmak mümkün mü? update() ve annotate() belgelerinde birlikte kullanma hakkında bilgi yoktur.

+1

? SQL'de bir UPDATE yaparken, diğer tablolara katılmanın mümkün olduğunu düşünmüyorum. – user27478

+1

Evet, mümkün - alt sorgularla, örn. UPDATE t1 SET a = (SELECT SUM (c) t2'den t2.b'ye = t1.b) '; –

+0

Gerçekten ne yapmaya çalışıyorsunuz? 'SigningRelation' tablosundaki 'rating' sütununun tüm değerlerini toplamaya ve sonra 'Relation' tablosunda yeni bir satır olarak kaydetmeye mi çalışıyorsunuz? – phourxx

cevap

-2

Bunu gerçekten yapamazsınız. Bazı ince okumalar için update ve follow it through için the code'a bir göz atın.

Dürüst olmak gerekirse, bir Yönetici tanımında böyle bir şey yerleştirmenin nesi yanlış? Görünümünüze koymak istemediğiniz 3 satırı bir yöneticiye koyun, gerektiğinde bu yöneticiyi arayın. Ek olarak, daha az "sihir" yapıyorsunuz ve bir sonraki geliştirici kodunuza baktığında, birkaç WTF'ye başvurmak zorunda kalmayacaklar .. :)

Ayrıca, merak ettim ve size benziyor SQL Join with UPDATE statements'u kullanabilir, ancak bazı klasik SQL korsanlığıdır .. Bu nedenle eğer bu kadar eğimliyseniz, bunun için Djangos raw SQL işlevini kullanabilirsiniz;)

+4

"Dürüst olmak gerekirse, böyle bir şeyi Yönetici tanımına yerleştirmenin nesi yanlış?" Bu, DB'ye gönderilen * çok fazla * istek olabilir. Özellikle "bir SQL talebi" talep etti. Ayrıca, denediğim örneklerin okunması kolay ve sihir gibi olmadığını düşünüyorum. –

+1

Geçtiğimiz günlerde bir SQL sorgusu elle yazmak zorunda kaldım çünkü düzgün bir şekilde yazıldığı için 200 ms sürdüm, bir güncelleme görünümü kullanırken 30 dakika beklemek zorunda kaldım. İşte sebebi bu. – Xowap

4

UPDATE bildirimi, GROUP BY desteğini desteklemez. Bakınız örn. PostgreSQL Docs, SQLite Docs. DjangoORM içinde

UPDATE relation 
SET rating = (SELECT SUM(rating) 
       FROM sign_relation 
       WHERE relation_id = relation.id) 

Eşdeğer:

from django.db.models.expressions import RawSQL 

Relation.objects.all(). \ 
    update(rating=RawSQL('SELECT SUM(rating) FROM signrelation WHERE relation_id = relation.id', [])) 

ya:

Böyle Someting gerek sen, sen gerektiği veritabanına birçok aramaları önlemek istiyorsanız

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, [])) 
+0

Son tavsiyenizi çalıştırabildiniz mi? .filter (ilişki = F ('relation__pk')) '' WHERE (relation.id = relation.id) 'a eşittir ve bu nedenle hiçbir şeye katılmaz mı? – jnns

+0

Güncelleme için teşekkürler. Bu .extra() 'ın yan tümce altındır! – jnns

-2

transaction.atomic kullanın.

daha Django belgelere okuyun: Kodunuzdaki Sonra

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() 

:

q = Realation.rating_objects.annotated() 

ne özelleştirmek için args/kwargs Ekle https://docs.djangoproject.com/en/1.9/topics/db/transactions/#controlling-transactions-explicitly

+0

'transaction.atomic', çağrıların sayısını azaltmaz, yalnızca tüm işlemin tamamen başarılı olduğunu veya hiçbir şeyi değiştirmeden başarısız olduğunu zorlar. –

-1

kendi özel nesneler yöneticisi tanımlayabilir Bu yönetici geri döner. postgres'in

0

Çözüm: Saf SQL bu bile mümkün emin değilim

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) 
İlgili konular