Django के साथ 'बल्क अपडेट' कैसे करें?


163

मैं Django के साथ एक तालिका को अपडेट करना चाहता हूं - कच्चे SQL में ऐसा कुछ:

update tbl_name set name = 'foo' where name = 'bar'

मेरा पहला परिणाम कुछ इस तरह है - लेकिन यह बुरा है, है ना?

list = ModelClass.objects.filter(name = 'bar')
for obj in list:
    obj.name = 'foo'
    obj.save()

वहाँ एक और अधिक सुंदर तरीका है?


1
आप बैच डालने के लिए देख रहे हो सकता है। एक पर नजर डालें stackoverflow.com/questions/4294088/...
प्रमोद

मुझे नया डेटा डालना पसंद नहीं है - बस मौजूदा अपडेट करें।
थॉमस श्वार्ज़ल

3
शायद select_for_update की मदद से? docs.djangoproject.com/en/dev/ref/models/querysets/…
Jure C.

ModelClassदृष्टिकोण के बारे में बुरा क्या नहीं है ? फिर Django को फ़ीड करें: stackoverflow.com/questions/16853649/…
Ciro Santilli 病 六四 as as ''

जवाबों:


256

अपडेट करें:

Django 2.2 संस्करण में अब एक बल्क_अपडेट है

पुराना उत्तर:

निम्नलिखित django प्रलेखन अनुभाग देखें

एक साथ कई ऑब्जेक्ट्स को अपडेट करना

संक्षेप में आप का उपयोग करने में सक्षम होना चाहिए:

ModelClass.objects.filter(name='bar').update(name="foo")

आप Fपंक्तियों को बढ़ाने के लिए वस्तुओं का उपयोग भी कर सकते हैं :

from django.db.models import F
Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)

दस्तावेज देखें ।

हालाँकि, ध्यान दें कि:

  • यह ModelClass.saveविधि का उपयोग नहीं करेगा (इसलिए यदि आपके अंदर कुछ तर्क है तो यह ट्रिगर नहीं होगा)।
  • कोई django सिग्नल उत्सर्जित नहीं किया जाएगा।
  • आप .update()एक कटा हुआ क्वेरी पर प्रदर्शन नहीं कर सकते , यह एक मूल क्वेरी पर होना चाहिए ताकि आपको .filter()और .exclude()विधियों पर झुकना पड़े ।

27
ध्यान दें कि उपयोग न करने के परिणामस्वरूप save(), "संशोधित" कॉलम वाले DateTimeFieldफ़ील्ड auto_now=Trueअपडेट नहीं किए जाएंगे।
आर्थर

3
लेकिन ModelClass.objects.filter(name = 'bar').update(name="foo")बल्क अपडेट के उद्देश्य को पूरा नहीं करता है, अगर मेरे पास अलग-अलग आईडी के लिए अलग-अलग डेटा है तो मैं लूप का उपयोग किए बिना कैसे कर सकता हूं?
शशांक

@ शशि मुझे यकीन नहीं है कि अगर मैं आपको सही मिला, लेकिन मैंने जवाब में उदाहरण जोड़ा।
जेबी

@ शशांक क्या आपने अभी तक अपने मामले का कोई समाधान पाया है? मेरा भी यही हाल है।
सौरव प्रेम

F ऑब्जेक्ट्स को .update मेथड में विभिन्न मॉडलों को संदर्भित करने के लिए उपयोग नहीं किया जा सकता ... उदाहरण के लिए आप उपयोग नहीं कर सकते Entry.objects.all().update(title=F('blog__title'))। डॉक्स में इसका एक छोटा सा उल्लेख है। यदि आप अपनी प्रविष्टियों को अपडेट करने के लिए किसी अन्य मॉडल से डेटा खींचना चाहते हैं, तो आपको एक लूप चलाना होगा
sean.hudson

31

GitHub पर यहांdjango-bulk-update पाए जाने वाले उपयोग पर विचार करें ।

इंस्टॉल: pip install django-bulk-update

लागू करें: (कोड सीधे परियोजनाओं से लिया गया ReadMe फ़ाइल)

from bulk_update.helper import bulk_update

random_names = ['Walter', 'The Dude', 'Donny', 'Jesus']
people = Person.objects.all()

for person in people:
    r = random.randrange(4)
    person.name = random_names[r]

bulk_update(people)  # updates all columns using the default db

अपडेट: जैसा कि मार्क टिप्पणियों में बताते हैं कि यह एक साथ हजारों पंक्तियों को अपडेट करने के लिए उपयुक्त नहीं है। हालांकि यह छोटे बैचों के लिए 10 से 100 के लिए उपयुक्त है। आपके लिए सही बैच का आकार आपके CPU और क्वेरी जटिलता पर निर्भर करता है। यह उपकरण डंप ट्रक की तुलना में पहिया बैरो की तरह अधिक है।


16
मैंने django-बल्क-अपडेट की कोशिश की, और मैं व्यक्तिगत रूप से इसका उपयोग करने को हतोत्साहित करता हूं। यह आंतरिक रूप से एक एकल एसक्यूएल स्टेटमेंट बनाने के लिए है जो इस तरह दिखता है: अद्यतन "तालिका" सेट "फ़ील्ड" = सीस "आईडी" जब% s तब% s जब% s तब% s है [...] जहां आईडी है % s,% s, [...]); - यह कुछ पंक्तियों (जब बल्क अपडेटर की आवश्यकता नहीं है) के लिए सभी प्रकार की सही है, लेकिन 10,000 के साथ, क्वेरी इतनी जटिल है, कि सीपीयू के साथ अधिक समय बिताता है 100% क्वेरी को समझने में, जब तक यह डिस्क को लिखने से बचाता है। ।
मार्क गार्सिया

1
@MarcGarcia अच्छा बिंदु। मैंने पाया कि कई डेवलपर्स अपने प्रभाव को जाने बिना बाहरी पुस्तकालयों का उपयोग करते हैं
Dejell

3
@MarcGarcia मैं असहमत हूं कि बल्क अपडेट मूल्यवान नहीं है और केवल तभी जरूरत होती है जब हजारों अपडेट जरूरी होते हैं। एक बार में 10,000 पंक्तियों का उपयोग करना आपके द्वारा बताए गए कारणों के लिए उचित नहीं है, लेकिन एक बार में 50 पंक्तियों को अपडेट करने के लिए इसका उपयोग 50 अलग-अलग अपडेट अनुरोधों के साथ db को हिट करने की तुलना में बहुत अधिक कुशल है।
नू एवरेस्ट

3
मैंने पाया सबसे अच्छा समाधान हैं: ए) @ ट्रांजेक्शन @ एटोमिक डेकोरेटर का उपयोग करते हैं, जो एकल लेनदेन का उपयोग करके प्रदर्शन में सुधार करता है, या बी) अस्थायी तालिका में एक थोक सम्मिलित करता है, और फिर अस्थायी तालिका से मूल एक तक अद्यतन करता है।
मार्क गार्सिया

1
मुझे पता है कि यह एक पुराना धागा है, लेकिन वास्तव में CASE / WHERE एकमात्र तरीका नहीं है। PostgreSQL के लिए अन्य दृष्टिकोण हैं, लेकिन वे DB विशिष्ट हैं जैसे stackoverflow.com/a/18799497 हालांकि मुझे यकीन नहीं है कि यह एएनएसआई एसक्यूएल में संभव है
इलियन इलिव

21

Django 2.2 संस्करण में अब एक bulk_updateविधि ( नोट्स जारी करें ) है।

https://docs.djangoproject.com/en/stable/ref/models/querysets/#bulk-update

उदाहरण:

# get a pk: record dictionary of existing records
updates = YourModel.objects.filter(...).in_bulk()
....
# do something with the updates dict
....
if hasattr(YourModel.objects, 'bulk_update') and updates:
    # Use the new method
    YourModel.objects.bulk_update(updates.values(), [list the fields to update], batch_size=100)
else:
    # The old & slow way
    with transaction.atomic():
        for obj in updates.values():
            obj.save(update_fields=[list the fields to update])


8

यदि आप पंक्तियों के संग्रह पर समान मान सेट करना चाहते हैं , तो आप किसी भी क्वेरी अवधि के साथ संयुक्त अद्यतन () विधि का उपयोग करके सभी पंक्तियों को एक क्वेरी में अपडेट कर सकते हैं:

some_list = ModelClass.objects.filter(some condition).values('id')
ModelClass.objects.filter(pk__in=some_list).update(foo=bar)

यदि आप कुछ शर्तों के आधार पर विभिन्न मूल्यों के साथ पंक्तियों के संग्रह को अपडेट करना चाहते हैं, तो आप सर्वोत्तम स्थिति में मूल्यों के अनुसार अपडेट को बैच सकते हैं। मान लीजिए कि आपके पास 1000 पंक्तियाँ हैं जहाँ आप X मानों में से किसी एक को स्तंभ सेट करना चाहते हैं, तो आप पहले से बैच तैयार कर सकते हैं और उसके बाद केवल X अद्यतन-क्वेरीज़ चला सकते हैं (प्रत्येक अनिवार्य रूप से ऊपर दिए गए पहले उदाहरण के रूप में) + प्रारंभिक चयन -query।

यदि प्रत्येक पंक्ति को एक विशिष्ट मूल्य की आवश्यकता होती है तो प्रति अपडेट एक क्वेरी से बचने का कोई तरीका नहीं है। शायद अन्य आर्किटेक्चर जैसे CQRS / Event सोर्सिंग में देखें, यदि आपको इस बाद वाले मामले में प्रदर्शन की आवश्यकता है।


1

वस्तुओं की आईटी रिटर्न संख्या तालिका में अपडेट की जाती है।

update_counts = ModelClass.objects.filter(name='bar').update(name="foo")

बल्क अपडेट और अधिक जानकारी प्राप्त करने के लिए आप इस लिंक को देख सकते हैं। थोक अद्यतन और बनाएँ

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.