2010-02-14 14 views
15

अगर हम एक प्रोफ़ाइल कैसे Django की सिफारिश की स्थापना की:Django विदेशी वस्तु को हटा दें?

class Profile(models.Model): 
    user = models.ForeignKey(User, unique=True) 

फिर जब आप Django व्यवस्थापक से User वस्तु हटा सकते हैं, यह अपने प्रोफ़ाइल too.This हटाता है, क्योंकि प्रोफ़ाइल उपयोगकर्ता के लिए एक विदेशी कुंजी है और यह चाहता है रेफरेंसियल अखंडता की रक्षा के लिए। हालांकि, मैं यह कार्यक्षमता चाहता हूं भले ही सूचक दूसरी तरफ जा रहा हो। उदाहरण के लिए, मेरी Profile वर्ग पर मेरे पास है:

shipper = models.ForeignKey(Shipper, unique=True, blank=True, null=True) 
carrier = models.ForeignKey(Carrier, unique=True, blank=True, null=True) 
affiliat = models.ForeignKey(Affiliate, unique=True, blank=True, null=True, verbose_name='Affiliate') 

और मैं यह चाहता हूँ कि यदि आप Profile हटाना उसे हटा देंगे जुड़े shipper/कैरियर/सहबद्ध वस्तुओं (मुझे मत पूछो क्यों Django बनाया " संबद्ध "कुछ अजीब कीवर्ड)। चूंकि शिपर्स, वाहक और सहयोगी उपयोगकर्ता के प्रकार होते हैं, और यह शेष डेटा के बिना अस्तित्व में नहीं आता है (कोई भी एक के रूप में लॉग इन करने में सक्षम नहीं होगा)।

कारण मैं, अन्य वस्तुओं पर चाबियाँ डाल नहीं किया है आंतरिक रूप से हर बार जब मैं जाँच करने के लिए उपयोगकर्ता था किस प्रकार ... चाहता था उन सभी तालिकाओं में शामिल होने क्योंकि तब Django होता

+0

"संबद्ध" निश्चित रूप से Django में "किसी प्रकार का विचित्र कीवर्ड" नहीं है। मैं "संबद्ध" नामक एक फ़ील्ड के साथ एक मॉडल बना सकता हूं और इसके साथ काम कर सकता हूं बस मेरे कोड में ठीक है। –

+0

यह बहुत अजीब है। सब कुछ ठीक काम करता है लेकिन यह व्यवस्थापक खंड में प्रकट होने से इंकार कर देता है। क्या आपने इसे देखा? एक सप्ताह पहले एसवीएन चेकआउट। – mpen

उत्तर

10

एक post_delete संकेत का उपयोग करते समय के रूप में बर्नार्डो द्वारा वर्णित के ऊपर एक ठीक दृष्टिकोण है, कि अच्छी तरह से काम करेगा, मैं अनावश्यक रूप से मानक कार्यक्षमता के लिए व्यवहार जोड़कर थोड़ा के रूप में आदमियत संभव के रूप में संकेतों का उपयोग कर के रूप में मुझे लगता है कि यह आपके कोड convolutes से बचने की कोशिश उन स्थानों पर जहां कोई उम्मीद कर सकता है।

मैं ऊपर ओवरराइडिंग विधि पसंद करता हूं, हालांकि, फ़ेलिक्स द्वारा दिए गए उदाहरण में एक घातक दोष है; हटाएँ() फ़ंक्शन यह ऐसा दिखाई देगा अधिभावी है:

def delete(self, using=None): 
    using = using or router.db_for_write(self.__class__, instance=self) 
    assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname) 

    collector = Collector(using=using) 
    collector.collect([self]) 
    collector.delete() 

सूचना पैरामीटर 'का उपयोग कर', ज्यादातर मामलों में हम खाली तर्क के साथ हटाना() तो हम भी ज्ञात हो सकता है यह वहाँ था कहते हैं। उपर्युक्त उदाहरण में इस पैरामीटर को ओवरराइड करके दफन किया गया है और सुपरक्लास कार्यक्षमता को नहीं देख रहा है, अगर प्रोफ़ाइल को हटाने पर 'उपयोग' पैरामीटर को पास करने वाला कोई व्यक्ति अप्रत्याशित व्यवहार का कारण बनता है। कि बचने के लिए, हम उसके डिफ़ॉल्ट Lika तो साथ साथ तर्क को संरक्षित करने के लिए सुनिश्चित करें होगा: अधिभावी दृष्टिकोण के लिए

class Profile(models.Model): 
# ... 

def delete(self, using=None): 
    if self.shipper: 
     self.shipper.delete() 
    if self.carrier: 
     self.carrier.delete() 
    if self.affiliat: 
     self.affiliat.delete() 
    super(Profile, self).delete(using) 

एक ख़तरा है, तथापि, कि हटाना है() स्पष्ट रूप से थोक पर डाटाबेस रिकॉर्ड प्रति बुलाया नहीं प्राप्त करता है हटा देता है, इसका मतलब यह है कि यदि आप एक ही समय में एकाधिक प्रोफाइल को हटाना चाहते हैं और ओवरराइडिंग व्यवहार (उदाहरण के लिए django क्वेरीसेट पर कॉलिंग .delete() को कॉल करना चाहते हैं) तो आपको डिलीट सिग्नल का लाभ उठाने की आवश्यकता होगी (जैसा कि बर्नार्डो द्वारा वर्णित है) या आपको अलग-अलग (महंगे और बदसूरत) को हटाने वाले प्रत्येक रिकॉर्ड के माध्यम से इसे फिर से शुरू करने की आवश्यकता होगी।

+0

यह निर्दिष्ट करने की आवश्यकता नहीं है कि उत्तर देने पर आप जवाब क्यों देते हैं, और इसके लिए आपको क्रेडिट भी मिलता है – dashesy

+0

ध्यान दें कि हटाएं () किसी ऑब्जेक्ट के लिए विधि को क्वेरीबेट का उपयोग करके थोक में ऑब्जेक्ट्स को हटाते समय जरूरी नहीं कहा जाता है। यह सुनिश्चित करने के लिए कि अनुकूलित डिलीट तर्क निष्पादित हो जाता है, आप pre_delete और/या post_delete संकेतों का उपयोग कर सकते हैं। https://docs.djangoproject.com/en/1.9/topics/db/models/#overriding-model-methods – dnaranjo

+0

@dnaranjo हां, यह सब मेरे उत्तर के अंत में सूचीबद्ध नुकसान में रखी गई है। हालांकि, टिप्पणी करने के लिए धन्यवाद, उम्मीद है कि जो कोई भी पूरे उत्तर को नहीं पढ़ता है, वह आपकी टिप्पणियों को पढ़कर संभावित नुकसान उठाएगा, और उनकी व्यक्तिगत जरूरतों के लिए शिक्षित निर्णय लेने में सहायता करेगा। – krayzk

5

आप कर सकते हैं override the delete() प्रोफ़ाइल वर्ग की विधि और वास्तविक प्रोफ़ाइल को हटाने से पहले इस विधि में अन्य ऑब्जेक्ट्स को हटाएं।

कुछ की तरह:

class Profile(models.Model): 
    # ... 

    def delete(self): 
     if self.shipper: 
      self.shipper.delete() 
     if self.carrier: 
      self.carrier.delete() 
     if self.affiliat: 
      self.affiliat.delete() 
     super(Profile, self).delete() 
+0

अच्छा लगता है, लेकिन जब मैं Django व्यवस्थापक के माध्यम से सामान हटाता हूं तो 'हटाएं()' विधि कभी नहीं कहती है ...? – mpen

+2

@ मार्क: जब आप एक ऑब्जेक्ट हटाते हैं तो कम से कम काम करना चाहिए। कई ऑब्जेक्ट्स को हटाने के साथ एक समस्या प्रतीत होती है: http://code.djangoproject.com/ticket/10751 –

5

एक बेहतर तरीका यह करने के लिए और उस वस्तु के नष्ट विधि के साथ काम करता है और के हटाने के विधि post_delete संकेत उपयोग कर रहा है, जैसा कि आप documentation में देख सकते हैं क्वेरीसमूह।

आपके मामले में, अपने कोड काफी इस के समान होगा:

from django.db import models 
from django.dispatch import receiver 

@receiver(models.signals.post_delete, sender=Profile) 
def handle_deleted_profile(sender, instance, **kwargs): 
    if instance.shipper: 
     instance.shipper.delete() 
    if instance.carrier: 
     instance.carrier.delete() 
    if instance.affiliat: 
     instance.affiliat.delete() 

यह केवल Django 1.3 या अधिक से अधिक है क्योंकि post_delete संकेत इस Django संस्करण में जोड़ा गया है के लिए काम करता है।

संबंधित मुद्दे