2010-09-06 28 views
16

मैं एनोटेटेड मान का उपयोग कर क्वेरीसेट में सभी पंक्तियों को अपडेट करना चाहता हूं।एनोटेशन के साथ Django अद्यतन क्वेरीसेट

मैं एक साधारण मॉडल:

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) 

और मैं इस कोड awoid हैं:

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

और कुछ इस तरह का उपयोग करके एक एसक्यूएल-अनुरोध में अद्यतन करें:

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

काम नहीं करता है:

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

या

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

भी काम नहीं करता:

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

क्या यह संभव है इस उद्देश्य के लिए Django के ORM उपयोग करने के लिए? अपडेट() और एनोटेट() दस्तावेज़ों में एक साथ उपयोग करने के बारे में कोई जानकारी नहीं है।

+1

मैं शुद्ध एसक्यूएल में यकीन है कि यह भी संभव नहीं कर रहा हूँ? एसक्यूएल में अद्यतन करते समय, मुझे नहीं लगता कि अन्य तालिकाओं में शामिल होना संभव है। – user27478

+1

हां, यह संभव है - subqueries के माध्यम से, पूर्व। 'अद्यतन टी 1 सेट एक = (टी 2 से चयन एसयूएम (सी) जहां t2.b = t1.b)'; –

+0

आप वास्तव में क्या करने की कोशिश कर रहे हैं? क्या आप 'साइनिंगरेलेशन' तालिका पर कॉलम 'रेटिंग' के सभी मानों को जोड़ना चाहते हैं और फिर इसे 'रिलेशन' टेबल पर एक नई पंक्ति के रूप में सहेज सकते हैं? – phourxx

उत्तर

-2

आप वास्तव में ऐसा नहीं कर सकते हैं। कुछ अच्छे पढ़ने के लिए update और follow it through के लिए the code पर एक नज़र डालें।

ईमानदारी से, प्रबंधक परिभाषा में ऐसा कुछ करने में क्या गलत है? उन 3 लाइनों को रखें जिन्हें आप अपने विचार में प्रबंधक में नहीं रखना चाहते हैं, उस प्रबंधक को आवश्यकतानुसार कॉल करें। इसके अतिरिक्त, आप बहुत कम "जादू" कर रहे हैं और जब अगला डेवलपर आपके कोड को देखता है, तो उन्हें कुछ डब्ल्यूटीएफ का सहारा लेना पड़ेगा .. :)

इसके अलावा, मैं उत्सुक था और यह आपके जैसा दिखता है SQL Join with UPDATE statements उपयोग कर सकते हैं लेकिन यह कुछ क्लासिक एसक्यूएल hackery है .. तो अगर आप इच्छुक हैं तो, आप उस के लिए Djangos कच्चे एसक्यूएल कार्यक्षमता का उपयोग कर सकते हैं;)

+4

"ईमानदारी से, प्रबंधक परिभाषा में ऐसा कुछ करने में क्या गलत है?" यह डीबी को भेजे गए अनुरोधों का * बहुत * हो सकता है। उन्होंने विशेष रूप से "एक एसक्यूएल-अनुरोध" का अनुरोध किया। साथ ही, मुझे लगता है कि उनके द्वारा किए गए उदाहरण पढ़ने के लिए आसान हैं और जादू की तरह नहीं। –

+1

हाल ही में मुझे मैन्युअल रूप से एक SQL क्वेरी लिखनी पड़ी क्योंकि उचित रूप से लिखा गया यह निष्पादित करने के लिए 200ms लिया गया, जबकि एक अद्यतन देखो का उपयोग करते समय मुझे 30 मिनट का इंतजार करना पड़ा। यही वजह है। – Xowap

4

UPDATE बयान GROUP BY समर्थन नहीं करता। उदाहरण देखें PostgreSQL Docs, SQLite Docs

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

DjangoORM में समतुल्य:

from django.db.models.expressions import RawSQL 

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

या:

आप इस तरह someting जरूरत

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

क्या आप अपनी आखिरी सिफारिश चलाने में सक्षम थे? '.filter (संबंध = एफ ('relation__pk') नहीं है '' WHERE (relation.id = relation.id)' के बराबर है और इसलिए कुछ भी शामिल नहीं है? – jnns

+0

अद्यतन करने के लिए धन्यवाद। वह '.extra() 'खंड सोने है! – jnns

-2

आप डेटाबेस के लिए कई कॉल से बचने के लिए, आपको चाहिए चाहते हैं transaction.atomic का उपयोग करें।

Django प्रलेखन पर और अधिक पढ़ें:

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

क्या अनुकूलित करने के लिए जोड़े आर्ग/kwargs https://docs.djangoproject.com/en/1.9/topics/db/transactions/#controlling-transactions-explicitly

+0

'credit.atomic' कॉल की संख्या को कम नहीं करता है, यह केवल यह लागू करता है कि पूरा लेनदेन या तो कुछ भी संशोधित किए बिना पूरी तरह सफल हो जाता है या विफल रहता है। –

-1

आप अपने स्वयं के कस्टम वस्तुओं प्रबंधक परिभाषित कर सकते हैं यह प्रबंधक वापस आता है। postgres के लिए

0

वर्कअराउंड:

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) 
संबंधित मुद्दे