Django मॉडल पर on_delete क्या करता है?


348

मैं Django से काफी परिचित हूं, लेकिन हाल ही में वहां देखा on_delete=models.CASCADEगया कि मॉडल के साथ एक विकल्प मौजूद है , मैंने उसी के लिए प्रलेखन की तलाश की है, लेकिन इसके अलावा कुछ भी नहीं मिला:

Django में बदला 1.9:

on_deleteअब दूसरी स्थिति तर्क के रूप में इस्तेमाल किया जा सकता है (पहले यह आमतौर पर केवल एक खोजशब्द तर्क के रूप में पारित किया गया था)। यह Django 2.0 में एक आवश्यक तर्क होगा।

उपयोग का एक उदाहरण मामला है

from django.db import models

class Car(models.Model):
    manufacturer = models.ForeignKey(
        'Manufacturer',
        on_delete=models.CASCADE,
    )
    # ...

class Manufacturer(models.Model):
    # ...
    pass

On_delete क्या करता है? ( मुझे लगता है कि मॉडल हटाए जाने पर किए जाने वाले कार्यों का अनुमान है )

क्या करता models.CASCADEहै? ( प्रलेखन में कोई संकेत )

अन्य विकल्प उपलब्ध हैं ( यदि मेरा अनुमान सही है )?

इस के लिए प्रलेखन कहाँ रहता है?


इसी तरह के सवाल का जवाब भी है stackoverflow.com/questions/47914325/…
HelenM

1
इस तरह के प्रश्न का पाठ अब इस उत्तर पर, नीचे सूचीबद्ध है। यह "FYI करना शुरू करता है, मॉडल में on_delete पैरामीटर जैसा दिखता है उससे पीछे की ओर है।" यह मूल उत्तरों की तुलना में बहुत अधिक विवरण प्रदान करता है।
हेलेनम

जवाबों:


782

संदर्भित ऑब्जेक्ट हटाए जाने पर अपनाने के लिए यह व्यवहार है। यह django के लिए विशिष्ट नहीं है, यह एक SQL मानक है।

इस तरह की घटना होने पर 6 संभावित कार्रवाई करने के लिए हैं:

  • CASCADE: जब संदर्भित ऑब्जेक्ट को हटा दिया जाता है, तो उसके संदर्भ वाली वस्तुओं को भी हटा दें (जब आप उदाहरण के लिए ब्लॉग पोस्ट हटाते हैं, तो आप टिप्पणियों को भी हटाना चाह सकते हैं)। एसक्यूएल समकक्ष CASCADE:।
  • PROTECT: संदर्भित वस्तु को हटाने से मना करें। इसे हटाने के लिए आपको सभी वस्तुओं को हटाना होगा जो इसे मैन्युअल रूप से संदर्भित करते हैं। एसक्यूएल समकक्ष RESTRICT:।
  • SET_NULL: NULL के संदर्भ को सेट करें (फ़ील्ड को अशक्त बनाने की आवश्यकता है)। उदाहरण के लिए, जब आप किसी उपयोगकर्ता को हटाते हैं, तो आप उन टिप्पणियों को ब्लॉग पोस्ट पर रखना चाह सकते हैं, लेकिन कहते हैं कि यह एक अनाम (या हटाए गए) उपयोगकर्ता द्वारा पोस्ट किया गया था। एसक्यूएल समकक्ष SET NULL:।
  • SET_DEFAULT: डिफ़ॉल्ट मान सेट करें। एसक्यूएल समकक्ष SET DEFAULT:।
  • SET(...): दिए गए मान को सेट करें। यह एक SQL मानक का हिस्सा नहीं है और पूरी तरह से Django द्वारा नियंत्रित किया जाता है।
  • DO_NOTHING: संभवतः यह एक बहुत बुरा विचार है क्योंकि यह आपके डेटाबेस में अखंडता के मुद्दे पैदा करेगा (एक ऐसी वस्तु का संदर्भ देना जो वास्तव में मौजूद नहीं है)। एसक्यूएल समकक्ष NO ACTION:।

स्रोत: Django प्रलेखन

उदाहरण के लिए PostGreSQL के प्रलेखन को भी देखें ।

ज्यादातर मामलों में, CASCADEअपेक्षित व्यवहार है, लेकिन प्रत्येक विदेशी के लिए, आपको हमेशा अपने आप से पूछना चाहिए कि इस स्थिति में अपेक्षित व्यवहार क्या है। PROTECTऔर SET_NULLअक्सर उपयोगी होते हैं। CASCADEजहाँ यह नहीं होना चाहिए वहां सेटिंग , केवल एक उपयोगकर्ता को हटाकर, अपने सभी डेटाबेस को कैस्केड में हटा सकता है।


कैस्केड दिशा स्पष्ट करने के लिए अतिरिक्त नोट

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

आपके डेटाबेस में, एक विदेशी कुंजी को मूल रूप से एक पूर्णांक फ़ील्ड द्वारा दर्शाया जाता है, जो मूल्य विदेशी वस्तु की प्राथमिक कुंजी है। मान लीजिए कि आपके पास एक प्रविष्टि comment_A है , जिसमें एक प्रविष्टि लेख के लिए एक विदेशी कुंजी है_ । यदि आप प्रविष्टि comment_A को हटाते हैं , तो सब कुछ ठीक है, Article_B बिना टिप्पणी_ के रहते थे और यदि इसे हटा दिया गया तो परेशान न हों। फिर भी, यदि आप लेख_ को हटाते हैं , तो टिप्पणी_ए पैनिक! यह कभी नहीं के बिना रहते थे article_B और यह जरूरत है, यह उसके गुण का हिस्सा ( article=article_Bहै, लेकिन क्या * article_B ** है ???)। यह वह जगह है जहां on_deleteइस अखंडता त्रुटि को हल करने के लिए कदम है, या तो कह कर:

  • "नहीं! कृपया! नहीं! मैं आपके बिना नहीं रह सकता!" (जिसे PROTECTSQL भाषा में कहा गया है)
  • "ठीक है, अगर मैं तुम्हारा नहीं हूँ, तो मैं किसी का नहीं हूँ" (जो कहा जाता है SET_NULL)
  • "अलविदा दुनिया, मैं आर्टिकल_ के बिना नहीं रह सकता" और आत्महत्या (यह CASCADEव्यवहार है)।
  • "यह ठीक है, मुझे अतिरिक्त प्रेमी मिल गया है, मैं अभी से Article_C का संदर्भ लूंगा" ( SET_DEFAULT, या यहां तक ​​कि SET(...))।
  • "मैं वास्तविकता का सामना नहीं कर सकता, मैं आपका नाम पुकारता रहूंगा, भले ही वह एकमात्र चीज मेरे पास बची हो!" ( DO_NOTHING)

मुझे आशा है कि यह झरना दिशा को स्पष्ट करता है। :)


19
एक मूर्खतापूर्ण प्रश्न, लेकिन कैस्केड हमेशा एक दिशात्मक अधिकार होना चाहिए? यानी अगर Comment कोई विदेशी कुंजी है BlogPostतो BlogPost हटाने के लिए टिप्पणी को हटा देना चाहिए, लेकिन टिप्पणी को हटाकर RDP की परवाह किए बिना BlogPost को नहीं हटाना चाहिए?
एंथनी मैनिंग-फ्रैंकलिन

20
@AnthonyManningFranklin ज़रूर। हटाए जाने पर केवल ट्रिगर किया जाता है जब एक संदर्भ "टूटा हुआ" होता है। जब आप किसी टिप्पणी को हटाते हैं तो ऐसा नहीं होता, क्योंकि आप उसी समय में संदर्भ हटा देते हैं।
एंटोनी पिंसार्ड

6
सवाल मूर्खतापूर्ण नहीं है; मुझे वह स्पष्टीकरण भी चाहिए। इसलिए यहाँ हम मानते हैं कि संबंध यूनी-लेटरल है, रिश्ते का स्वामी वह है Comment, जिसके पास अपनी तालिका में FK फ़ील्ड है, जबकि अगर हम वास्तविक जीवन के मॉडल के बारे में बात करते हैं तो BlogPost"मालिक" हैं Comment। अच्छा।
पश्चिमीगुण

3
ध्यान देने वाली महत्वपूर्ण बात यह है कि Django में on_delete सेट करने से डेटाबेस में स्वयं पर DELETE क्लॉज नहीं बनता है। निर्दिष्ट व्यवहार (जैसे CASCADE) केवल Django के माध्यम से किए गए डिलीट को प्रभावित करेगा, न कि सीधे डेटाबेस में किए गए कच्चे डिलीट को।
जोएमआरआर 2

2
अंत में वे उद्धरण ऐसे लगते हैं जैसे वे रॉय लिचेंस्टीन की कॉमिक बुक पैनल से सीधे खींचे गए हों! अद्भुत
हवाई

42

इस on_deleteविधि का उपयोग Django को मॉडल उदाहरणों के साथ क्या करना है जो आपके द्वारा हटाए गए मॉडल के उदाहरण पर निर्भर करते हैं। (जैसे कोई ForeignKeyरिश्ता)। on_delete=models.CASCADEDjango बताता हटाने प्रभाव यानी साथ ही निर्भर मॉडल को हटाने के लिए जारी झरना।

यहाँ एक और अधिक ठोस उदाहरण है। मान लें Authorकि आपके पास एक मॉडल है जो ForeignKeyएक Bookमॉडल में है। अब, यदि आप Authorमॉडल का एक उदाहरण हटाते हैं, तो Django को पता नहीं होगा Bookकि मॉडल के उदाहरणों के साथ क्या करना है जो मॉडल के उस उदाहरण पर निर्भर करते हैं Authoron_deleteविधि Django क्या उस स्थिति में क्या करना बताता है। सेटिंग on_delete=models.CASCADEDjango को हटाने के प्रभाव को रोकने के लिए निर्देश देगा अर्थात आपके द्वारा हटाए गए मॉडल के उदाहरण Bookपर निर्भर सभी Authorमॉडल उदाहरणों को हटा दें।

नोट: on_deleteDjango 2.0 में एक आवश्यक तर्क बन जाएगा। पुराने संस्करणों में यह चूक करता है CASCADE

यहाँ संपूर्ण आधिकारिक दस्तावेज है।


37

FYI करें, on_deleteमॉडल में पैरामीटर जैसा दिखता है उससे पीछे की ओर है। आपने on_deletedjango को यह बताने के लिए एक मॉडल पर एक विदेशी कुंजी (FK) डाल दी है कि यदि FK प्रविष्टि जिसे आप अपने रिकॉर्ड पर इंगित कर रहे हैं, हटा दी जाए तो क्या करें। विकल्प हमारी दुकान का इस्तेमाल किया है सबसे कर रहे हैं PROTECT, CASCADEऔर SET_NULL। यहाँ बुनियादी नियम दिए गए हैं:

  1. का प्रयोग करें PROTECTजब आपके FK एक लुक-अप तालिका की ओर इशारा करते है कि वास्तव में नहीं बदल रहा है किया जाना चाहिए और कहा कि निश्चित रूप से परिवर्तन करने के लिए अपनी मेज का कारण नहीं होना चाहिए। यदि कोई भी उस लुक-अप टेबल पर एक प्रविष्टि को हटाने की कोशिश करता है, PROTECTतो उसे किसी भी रिकॉर्ड से बंधे होने पर उसे हटाने से रोकता है। यह केवल आपके रिकॉर्ड को हटाने से django को रोकता है क्योंकि इसने लुक-अप टेबल पर एक प्रविष्टि हटा दी है। यह अंतिम भाग महत्वपूर्ण है। अगर कोई मेरी लिंग तालिका से "महिला" लिंग को हटाना चाहता था, तो मैं मुख्य रूप से नहीं चाहूंगा कि मेरे पर्सन टेबल में मौजूद किसी भी और सभी लोगों को तुरंत हटा दिया जाए।
  2. CASCADEजब आपका FK "पैरेंट" रिकॉर्ड की ओर इशारा कर रहा हो तब उपयोग करें । तो, एक व्यक्ति कई PersonEthnicity प्रविष्टियों हो सकता है अगर (वह / वह अमेरिकी भारतीय, काले और सफेद हो सकता है), और कहा कि व्यक्ति है नष्ट कर दिया, मैं वास्तव में चाहते हैं चाहते हैं किसी भी "बच्चा" PersonEthnicity प्रविष्टियों हटाए जाने के लिए। वे व्यक्ति के बिना अप्रासंगिक हैं।
  3. उपयोग करें SET_NULLजब आप चाहते हैं कि लोगों को एक लुक-अप टेबल पर एक प्रविष्टि को हटाने की अनुमति दी जाए, लेकिन आप अभी भी अपने रिकॉर्ड को संरक्षित करना चाहते हैं। उदाहरण के लिए, यदि एक व्यक्ति के पास हाईस्कूल हो सकता है, लेकिन यह वास्तव में मेरे लिए मायने नहीं रखता है अगर वह हाई-स्कूल मेरे लुक-अप टेबल पर चला जाता है, तो मैं कहूंगा on_delete=SET_NULL। यह मेरा व्यक्ति रिकॉर्ड वहाँ छोड़ देगा; यह सिर्फ हाई-स्कूल एफके को मेरे व्यक्ति पर शून्य करने के लिए निर्धारित करेगा। जाहिर है, आपको null=Trueउस एफके पर अनुमति देनी होगी ।

यहाँ एक मॉडल का उदाहरण दिया गया है जो तीनों चीजों को करता है:

class PurchPurchaseAccount(models.Model):
    id = models.AutoField(primary_key=True)
    purchase = models.ForeignKey(PurchPurchase, null=True, db_column='purchase', blank=True, on_delete=models.CASCADE) # If "parent" rec gone, delete "child" rec!!!
    paid_from_acct = models.ForeignKey(PurchPaidFromAcct, null=True, db_column='paid_from_acct', blank=True, on_delete=models.PROTECT) # Disallow lookup deletion & do not delete this rec.
    _updated = models.DateTimeField()
    _updatedby = models.ForeignKey(Person, null=True, db_column='_updatedby', blank=True, related_name='acctupdated_by', on_delete=models.SET_NULL) # Person records shouldn't be deleted, but if they are, preserve this PurchPurchaseAccount entry, and just set this person to null.

    def __unicode__(self):
        return str(self.paid_from_acct.display)
    class Meta:
        db_table = u'purch_purchase_account'

अंतिम टिडबिट के रूप में, क्या आप जानते हैं कि यदि आप निर्दिष्ट नहीं करते on_delete(या नहीं), तो डिफ़ॉल्ट व्यवहार क्या है CASCADE? इसका मतलब है कि अगर किसी ने आपकी लिंग तालिका में लिंग प्रविष्टि को हटा दिया है, तो उस लिंग के साथ किसी भी व्यक्ति के रिकॉर्ड भी हटा दिए गए हैं!

मैं कहूंगा, "यदि संदेह है, तो सेट करें on_delete=models.PROTECT।" फिर अपने आवेदन का परीक्षण करें। आप जल्दी से यह पता लगाएंगे कि कौन सा FK आपके अन्य डेटा को खतरे में डाले बिना अन्य मूल्यों को लेबल किया जाना चाहिए।

इसके अलावा, यह ध्यान देने योग्य है कि on_delete=CASCADEवास्तव में आपके किसी भी माइग्रेशन में नहीं जोड़ा गया है, यदि वह व्यवहार आप चुन रहे हैं। मुझे लगता है कि यह डिफ़ॉल्ट है, इसलिए on_delete=CASCADEकुछ भी नहीं डालने के रूप में एक ही बात है।


12

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

class City(models.Model):
    # define model fields for a city

class Property(models.Model):
    city = models.ForeignKey(City, on_delete = models.CASCADE)
    # define model fields for a property

और अब जब डेटाबेस से शहर को हटा दिया जाता है, तो सभी संबद्ध गुण (जैसे उस शहर में स्थित अचल संपत्ति) को भी डेटाबेस से हटा दिया जाएगा।

अब मैं अन्य विकल्पों की योग्यता का भी उल्लेख करना चाहता हूं, जैसे कि SET_NULL या SET_DEFAULT या यहां तक ​​कि DO_NOTING भी। मूल रूप से, प्रशासन के दृष्टिकोण से, आप उन रिकॉर्डों को "हटाना" चाहते हैं। लेकिन आप वास्तव में उन्हें गायब नहीं करना चाहते हैं। कई कारणों से। किसी व्यक्ति ने इसे गलती से या ऑडिटिंग और निगरानी के लिए हटा दिया होगा। और सादा रिपोर्टिंग। तो यह एक शहर से संपत्ति को "डिस्कनेक्ट" करने का एक तरीका हो सकता है। फिर, यह इस बात पर निर्भर करेगा कि आपका आवेदन कैसे लिखा गया है।

उदाहरण के लिए, कुछ अनुप्रयोगों में एक फ़ील्ड "हटा दिया गया" है जो 0 या 1. है और उनके सभी खोज और सूची दृश्य आदि, कुछ भी जो रिपोर्ट में दिखाई दे सकते हैं या कहीं भी उपयोगकर्ता इसे सामने के छोर से एक्सेस कर सकते हैं, जो कुछ भी है उसे बाहर कर सकते हैं deleted == 1। हालाँकि, यदि आप एक कस्टम रिपोर्ट या एक कस्टम क्वेरी बनाते हैं, जो हटाए गए रिकॉर्ड की एक सूची को खींचने के लिए और यहां तक ​​कि यह देखने के लिए कि यह अंतिम बार कब संशोधित किया गया था (दूसरा फ़ील्ड) और किसके द्वारा (यानी जिसने इसे हटा दिया है और कब)। यह कार्यकारी दृष्टिकोण से बहुत फायदेमंद है।

और यह मत भूलो कि आप deleted = 0उन रिकॉर्डों के रूप में आकस्मिक विलोपन को वापस कर सकते हैं ।

मेरा कहना है कि अगर कोई कार्यशीलता है, तो उसके पीछे हमेशा एक कारण होता है। हमेशा एक अच्छा कारण नहीं। लेकिन एक कारण। और अक्सर एक अच्छा भी।


3
यह मददगार था क्योंकि यह स्पष्ट करता है कि CASCADE किस दिशा में होता है। यदि आप SQL कैस्केड से अपरिचित हैं, तो स्वीकृत उत्तर स्पष्ट नहीं है।
कोडस्क्ब्बल

धन्यवाद, आपका आभार है!
जॉर्ज मोगिलेवस्की

2
मैं इस उत्तर को
बढ़ाता

6

यहाँ आपके प्रश्न का उत्तर है जो कहता है: हम on_delete का उपयोग क्यों करते हैं?

जब किसी फॉरेनके द्वारा संदर्भित ऑब्जेक्ट को हटा दिया जाता है, तो Django डिफ़ॉल्ट रूप से SQL कसौटी पर DELETE CASCADE के व्यवहार का अनुकरण करता है और फॉरेनकेई युक्त ऑब्जेक्ट को भी हटा देता है। इस व्यवहार को on_delete तर्क निर्दिष्ट करके ओवरराइड किया जा सकता है। उदाहरण के लिए, यदि आपके पास एक अशक्त फॉरेनकेई है और आप चाहते हैं कि संदर्भित ऑब्जेक्ट को हटाए जाने पर इसे शून्य सेट किया जाए:

user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)

On_delete के लिए संभावित मान django.db.models में पाए जाते हैं:

कैस्केड: कैस्केड हटाता है; डिफ़ॉल्ट।

PROTECT: संदर्भित ऑब्जेक्ट को हटाकर प्रोटेक्टेअर, एक उपवर्ग django.db.IntegrityError को हटाकर रोकें।

SET_NULL: विदेशी केक को सेट करें; यह तभी संभव है जब अशक्त सत्य है।

SET_DEFAULT: फॉरेनके को इसके डिफ़ॉल्ट मान पर सेट करें; फॉरेनके के लिए एक डिफ़ॉल्ट सेट होना चाहिए।


सरल शब्द मेरे लिए यह स्पष्ट करते हैं कि एसवाईएल एसक्यूएल और डीजेंगो के साथ भी परिपक्व नहीं है। धन्यवाद।
wm.p1us

3

मान लीजिए कि आपके दो मॉडल हैं, एक का नाम पर्सन और दूसरे का नाम कंपनी है

परिभाषा के अनुसार, एक व्यक्ति एक से अधिक कंपनी बना सकता है।

एक कंपनी को ध्यान में रखते हुए एक और केवल एक ही व्यक्ति हो सकता है, हम चाहते हैं कि जब एक व्यक्ति को हटा दिया जाए कि उस व्यक्ति से जुड़ी सभी कंपनियां भी हटा दी जाएं।

तो, हम इस तरह एक व्यक्ति मॉडल बनाकर शुरू करते हैं

class Person(models.Model):
    id = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=20)

    def __str__(self):
        return self.id+self.name

फिर, कंपनी मॉडल इस तरह दिख सकता है

class Companies(models.Model):
    title = models.CharField(max_length=20)
    description=models.CharField(max_length=10)
    person= models.ForeignKey(Person,related_name='persons',on_delete=models.CASCADE)

on_delete=models.CASCADEमॉडल कंपनियों के उपयोग पर ध्यान दें । यानी सभी कंपनियों को तब हटाया जाता है जब वह व्यक्ति जो इसका मालिक है (वर्ग व्यक्ति का उदाहरण) हटा दिया गया है।


1

पहले से मौजूद कैस्केड (यानी झरना) में एफके जोड़ने के बारे में सोचकर "कैस्केड" की कार्यक्षमता के अपने मानसिक मॉडल को फिर से उन्मुख करें। इस झरने का स्रोत एक प्राथमिक कुंजी है। नष्ट हो जाते हैं।

इसलिए यदि आप FK के on_delete को "CASCADE" के रूप में परिभाषित करते हैं, तो आप इस FK के रिकॉर्ड को PK से उत्पन्न होने वाले डिलीट के कैस्केड में जोड़ रहे हैं। इस कैस्केड में एफके का रिकॉर्ड भाग ले सकता है या नहीं ("SET_NULL")। वास्तव में, एफके के साथ एक रिकॉर्ड भी हटाए जाने के प्रवाह को रोक सकता है! "PROTECT" के साथ एक बांध बनाएं।


0

CASCADE का उपयोग करने का अर्थ है वास्तव में संदर्भित रिकॉर्ड को हटाने के लिए Django को बताना। नीचे दिए गए पोल ऐप उदाहरण में: जब एक 'प्रश्न' डिलीट हो जाता है, तो यह विकल्प इस प्रश्न को हटा देगा।

उदाहरण प्रश्न: आपने हमारे बारे में कैसे सुना? (विकल्प: 1. मित्र 2. टीवी विज्ञापन 3. खोज इंजन 4. ईमेल प्रचार)

जब आप इस प्रश्न को हटाते हैं, तो यह तालिका से इन सभी चार विकल्पों को भी हटा देगा। ध्यान दें कि यह किस दिशा में बहती है। आपको on_delete = model.CASCADE को प्रश्न मॉडल में नहीं डालना है, इसे चॉइस में रखें।

from django.db import models



class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.dateTimeField('date_published')

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_legth=200)
    votes = models.IntegerField(default=0)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.