मैं एक Django मॉडल इंस्टेंस ऑब्जेक्ट को कैसे क्लोन करूं और डेटाबेस में सहेजूं?


260
Foo.objects.get(pk="foo")
<Foo: test>

डेटाबेस में, मैं एक और ऑब्जेक्ट जोड़ना चाहता हूं जो ऊपर दिए गए ऑब्जेक्ट की एक प्रति है।

मान लीजिए कि मेरी तालिका में एक पंक्ति है। मैं पहली पंक्ति वस्तु को दूसरी पंक्ति में एक अलग प्राथमिक कुंजी के साथ सम्मिलित करना चाहता हूं। मैं उसे कैसे कर सकता हूँ?

जवाबों:


437

बस अपनी वस्तु की प्राथमिक कुंजी बदलें और सहेजें () चलाएँ।

obj = Foo.objects.get(pk=<some_existing_pk>)
obj.pk = None
obj.save()

यदि आप ऑटो-जनरेट की चाहते हैं, तो नई कुंजी को किसी पर सेट न करें।

अधिक अद्यतन / सम्मिलित करें पर यहाँ

मॉडल उदाहरणों की नकल करने पर आधिकारिक डॉक्स: https://docs.djangoproject.com/en/2.2/topics/db/queries/#copying-model-instances


2
ध्यान देने योग्य बात यह है कि यह Django 1.2 को उद्धृत करता है, अब हम Django 1.4 तक हैं। यह काम करता है या नहीं, इसका परीक्षण नहीं किया गया है, लेकिन इस उत्तर का उपयोग किए बिना सुनिश्चित करें कि यह आपके लिए काम करता है।
जो

7
1.4.1 में ठीक काम करता है। यह संभवतः उन चीजों में से एक है जो लंबे समय तक काम करना जारी रखेगा।
13

8
मुझे दोनों को सेट करना था obj.pkऔर obj.idइस काम को करने के लिए Django 1.4
Petr Peller

3
@PetrPeller - डॉक्स का सुझाव है कि क्योंकि आप मॉडल वंशानुक्रम का उपयोग कर रहे हैं।
डोमिनिक रॉगर

12
नोट: अगर विदेशी चाबियां हैं, तो चीजें थोड़ी अधिक जटिल हो सकती हैं, वन 2 ओन और एम 2 एम शामिल (यानी, अधिक जटिल "डीप कॉपी" परिदृश्य हो सकते हैं)
बेन रॉबर्ट्स

135

डेटाबेस प्रश्नों के लिए Django प्रलेखन में मॉडल उदाहरणों की प्रतिलिपि बनाने वाला एक खंड शामिल है । मान लें कि आपकी प्राथमिक कुंजियाँ स्वचालित हैं, तो आपको वह ऑब्जेक्ट मिलता है जिसे आप कॉपी करना चाहते हैं, प्राथमिक कुंजी सेट करें Noneऔर ऑब्जेक्ट को सहेजें:

blog = Blog(name='My blog', tagline='Blogging is easy')
blog.save() # blog.pk == 1

blog.pk = None
blog.save() # blog.pk == 2

इस स्निपेट में, पहला save()मूल ऑब्जेक्ट बनाता है, और दूसरा save()कॉपी बनाता है।

यदि आप दस्तावेज़ीकरण पढ़ते रहते हैं, तो दो और जटिल मामलों को संभालने के तरीके भी हैं: (1) एक वस्तु की नकल करना जो एक मॉडल उपवर्ग का एक उदाहरण है, और (2) संबंधित वस्तुओं की नकल करना, जिसमें कई वस्तुओं को शामिल करना है -मनी संबंध


मिया के उत्तर पर ध्यान दें: पीके को सेट करना Noneमिया के उत्तर में उल्लिखित है, हालांकि इसे सामने और केंद्र में प्रस्तुत नहीं किया गया है। तो मेरा जवाब मुख्य रूप से उस विधि पर जोर देने के लिए कार्य करता है जैसा कि Django- अनुशंसित तरीका है।

ऐतिहासिक नोट: यह संस्करण 1.4 तक Django डॉक्स में समझाया नहीं गया था। यह 1.4 से पहले संभव हो गया है, हालांकि।

संभावित भविष्य की कार्यक्षमता: इस टिकट में पूर्वोक्त डॉक्स परिवर्तन किया गया था । टिकट के कमेंट थ्रेड पर, copyमॉडल कक्षाओं के लिए एक अंतर्निहित फ़ंक्शन को जोड़ने पर भी कुछ चर्चा हुई , लेकिन जहां तक ​​मुझे पता है कि उन्होंने अभी तक उस समस्या से निपटने का फैसला नहीं किया है। तो नकल के इस "मैनुअल" तरीके को शायद अब करना होगा।


46

यहां सावधान रहें। यह बेहद महंगा हो सकता है यदि आप किसी प्रकार के पाश में हैं और आप एक-एक करके वस्तुओं को प्राप्त कर रहे हैं। यदि आप डेटाबेस को कॉल नहीं करना चाहते हैं, तो बस करें:

from copy import deepcopy

new_instance = deepcopy(object_you_want_copied)
new_instance.id = None
new_instance.save()

यह इनमें से कुछ अन्य उत्तरों के समान काम करता है, लेकिन यह ऑब्जेक्ट को पुनः प्राप्त करने के लिए डेटाबेस कॉल नहीं करता है। यदि आप डेटाबेस में अभी तक मौजूद नहीं है, तो आप उस वस्तु की एक प्रतिलिपि बनाना चाहते हैं, तो यह भी उपयोगी है।


1
यह बहुत अच्छा काम करता है यदि आपके पास कोई वस्तु है, तो आप नई वस्तु में परिवर्तन करने और उसे सहेजने से पहले मूल वस्तु की गहरी नकल कर सकते हैं। फिर आप कुछ कंडीशन चेक कर सकते हैं और अगर वे पास हो जाते हैं तो उसके आधार पर, यानी ऑब्जेक्ट किसी अन्य टेबल में है, जिसे आप चेक कर रहे हैं, आप new_instance.id = original_instance.id सेट कर सकते हैं और सेव कर सकते हैं :) धन्यवाद!
राडटेक

2
यह काम नहीं करता है यदि मॉडल में कई विरासत स्तर हैं।
डेविड चेउंग

1
मेरे मामले में मैं मॉडल के लिए एक क्लोन विधि बनाना चाहता था, जो "स्व" चर का उपयोग करेगा और मैं बस स्वयं को सेट नहीं कर सकता। कोई भी नहीं, इसलिए यह समाधान एक आकर्षण की तरह काम करता है। मैंने नीचे दिए गए model_to_dict समाधान के बारे में सोचा था, लेकिन इसके लिए एक अतिरिक्त कदम की आवश्यकता है और इसमें संबंधों के माध्यम से एक ही मुद्दा होगा, जिसे मुझे वैसे भी मैन्युअल रूप से निपटना होगा, इसलिए मेरे लिए इसका कोई बड़ा प्रभाव नहीं है।
एंडरसन सैंटोस

32

नीचे दिए गए कोड का उपयोग करें:

from django.forms import model_to_dict

instance = Some.objects.get(slug='something')

kwargs = model_to_dict(instance, exclude=['id'])
new_instance = Some.objects.create(**kwargs)

8
model_to_dictएक excludeपैरामीटर लेता है , जिसका अर्थ है कि आपको अलग-अलग की आवश्यकता नहीं है pop:model_to_dict(instance, exclude=['id'])
जॉर्ज

20

यहाँ एक क्लोन स्निपेट है , जिसे आप अपने मॉडल में जोड़ सकते हैं जो ऐसा करता है:

def clone(self):
  new_kwargs = dict([(fld.name, getattr(old, fld.name)) for fld in old._meta.fields if fld.name != old._meta.pk]);
  return self.__class__.objects.create(**new_kwargs)

@ user426975 - आह, ओह ठीक है (मैंने इसे अपने उत्तर से हटा दिया है)।
डोमिनिक रॉजर

यकीन नहीं है कि यह एक Django संस्करण बात है, लेकिन ifअब उदाहरण if fld.name != old._meta.pk.nameकी nameसंपत्ति , यानी होने की जरूरत है _meta.pk
क्रिस

20

यह कैसे करना है Django1.4 में आधिकारिक Django डॉक्स में जोड़ा गया था

https://docs.djangoproject.com/en/1.10/topics/db/queries/#copying-model-instances

आधिकारिक उत्तर माया के उत्तर के समान है, लेकिन डॉक्स विरासत और संबंधित वस्तुओं के साथ कुछ कठिनाइयों को इंगित करते हैं, इसलिए आपको यह सुनिश्चित करना चाहिए कि आप डॉक्स पढ़ सकते हैं।


जब आप लिंक को खोलते हैं तो यह कहता है कि पेज नहीं मिला है
अमृत

Django 1.4 के लिए डॉक्स अब मौजूद नहीं हैं। मैं नवीनतम डॉक्स को इंगित करने के लिए उत्तर को अपडेट करूंगा।
माइकल बाइल्स्ट्रा

1
@MichaelBylstra एक अच्छा तरीका सदाबहार लिंक करने के लिए उपयोग करने के लिए है stable: URL में संस्करण संख्या के बजाय इस तरह docs.djangoproject.com/en/stable/topics/db/queries/...
Flimm

8

मैं स्वीकार किए गए उत्तर के साथ एक जोड़े में मिल गया है। यहाँ मेरा समाधान है।

import copy

def clone(instance):
    cloned = copy.copy(instance) # don't alter original instance
    cloned.pk = None
    try:
        delattr(cloned, '_prefetched_objects_cache')
    except AttributeError:
        pass
    return cloned

नोट: यह उन समाधानों का उपयोग करता है जो Django डॉक्स में आधिकारिक तौर पर स्वीकृत नहीं हैं, और वे भविष्य के संस्करणों में काम करना बंद कर सकते हैं। मैंने 1.9.13 में इसका परीक्षण किया।

पहला सुधार यह है कि यह आपको मूल उदाहरण का उपयोग करके, जारी रखने की अनुमति देता है copy.copy। यहां तक ​​कि अगर आप उदाहरण का पुन: उपयोग करने का इरादा नहीं रखते हैं, तो यह चरण ऐसा करने के लिए सुरक्षित हो सकता है यदि आप जिस क्लोन का उपयोग कर रहे हैं वह फ़ंक्शन के तर्क के रूप में पारित किया गया था। यदि नहीं, तो फ़ंक्शन के वापस आने पर कॉलर को अप्रत्याशित रूप से एक अलग उदाहरण होगा।

copy.copyवांछित तरीके से एक Django मॉडल उदाहरण की उथली प्रतिलिपि का उत्पादन करने के लिए लगता है। यह उन चीजों में से एक है जिन्हें मैंने दस्तावेज नहीं पाया था, लेकिन यह अचार और अनप्लिकिंग द्वारा काम करता है, इसलिए यह संभवतः अच्छी तरह से समर्थित है।

दूसरे, स्वीकृत उत्तर नए उदाहरण से जुड़े किसी भी पूर्वनिर्धारित परिणाम को छोड़ देगा। जब तक आप स्पष्ट रूप से कई रिश्तों की नकल नहीं करते हैं, तब तक उन परिणामों को नए उदाहरण के साथ संबद्ध नहीं किया जाना चाहिए। यदि आप पहले से तय किए गए रिश्तों को आगे बढ़ाते हैं, तो आपको ऐसे परिणाम मिलेंगे जो डेटाबेस से मेल नहीं खाते हैं। जब आप एक प्रीफ़ेट जोड़ते हैं तो वर्किंग कोड को तोड़ना एक बुरा आश्चर्य हो सकता है।

हटाना _prefetched_objects_cacheसभी प्रीफ़ेट को दूर करने का एक त्वरित और गंदा तरीका है। इसके बाद से कई एक्सेस काम करते हैं जैसे कि कोई प्रीफ़ैच नहीं था। एक अनड्रेस्केटेड प्रॉपर्टी का उपयोग करना, जो अंडरस्कोर से शुरू होता है, संभवतः संगतता समस्या के लिए पूछ रहा है, लेकिन यह अभी के लिए काम करता है।


मुझे यह काम करने में सक्षम था, लेकिन ऐसा लग रहा है कि यह पहले से ही 1.11 में बदल सकता है, क्योंकि मेरे पास एक संपत्ति थी _[model_name]_cache, जिसे एक बार हटा दिया गया था, मैं उस संबंधित मॉडल के लिए एक नई आईडी असाइन करने में सक्षम था, फिर कॉल करें save()। अभी भी साइड इफेक्ट्स हो सकते हैं जो मैंने अभी तक निर्धारित नहीं किए हैं।
trpt4him

यह अत्यंत महत्वपूर्ण जानकारी है यदि आप क्लास / मिक्सिन पर किसी फ़ंक्शन में क्लोनिंग कर रहे हैं, क्योंकि यह अन्यथा 'स्वयं' को गड़बड़ कर देगा और आप सभी भ्रमित हो जाएंगे।
एंड्रियास बर्गस्ट्रॉम्

5

किसी को भी pk सेट करना बेहतर नहीं है, पापी Django सही ढंग से आपके लिए एक pk बना सकता है

object_copy = MyObject.objects.get(pk=...)
object_copy.pk = None
object_copy.save()

3

यह मॉडल के उदाहरण को क्लोन करने का एक और तरीका है:

d = Foo.objects.filter(pk=1).values().first()   
d.update({'id': None})
duplicate = Foo.objects.create(**d)

0

कई वंशानुक्रम स्तर वाले मॉडल का क्लोन करने के लिए, नीचे>> = 2, या मॉडलसी

class ModelA(models.Model):
    info1 = models.CharField(max_length=64)

class ModelB(ModelA):
    info2 = models.CharField(max_length=64)

class ModelC(ModelB):
    info3 = models.CharField(max_length=64)

कृपया प्रश्न को यहाँ देखें ।


आह हाँ, लेकिन उस सवाल का एक स्वीकृत जवाब नहीं है! जाने के लिए रास्ता!
बोबार्ट

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