2011-04-11 3 views
11

क्या django pre_delete सिग्नल का उपयोग करके रिकॉर्ड हटाने को रद्द करने का कोई तरीका है?django सिग्नल में एक डिलीट को रद्द करने के लिए कैसे करें

उदाहरण:

def on_delete(sender,**kwargs): 
    if not <some condition>: 
    #cancel the deletion 
# else continue with the deletion 
pre_delete.connect(on_delete,sender=MyModel) 

और एक अन्य सवाल ही नहीं "है कि एक फ़ाइल को बदलने से पहले पहले मूल फ़ाइल हटाना " क्योंकि अभी यह है कि क्या मैं (कोड को देखने के एक मॉडल के लिए कहने के लिए एक रास्ता है नीचे) और मुझे यकीन नहीं है कि यह करने का यह सबसे अच्छा तरीका है या नहीं। (इस सुविधा Django 1.2 में वे स्वचालित रूप से फ़ाइल परिवर्तन पर या हटाने पर लेकिन Django 1.3 में हटाने पर उन्हें हटाया)

def on_save(sender,**kwargs): 
    obj = kwargs['instance'] 
    try: 
    id = obj.pk 
    # find the file 
    original_file = sender.objects.get(pk=id) 
    # delete the original file before uploading a new file 
    original_file.file.delete() 
    except .... 

pre_save.connect(on_save,sender=ModelWithFileUpload) 

अग्रिम

उत्तर

0

यह धन्यवाद संभव है जब उपयोग करके नहीं बनाया हो जाता है - Django सिग्नल में। सिग्नल पर "send()" और "send_robust()" विधियां 2-टुपल्स की एक सूची लौटाती हैं - (रिसीवर, प्रतिक्रिया)। इसलिए, यदि आपके पास प्रत्येक रिसीवर से प्रतिक्रियाओं को संभालने के लिए उचित कोड है, तो यह संभव है कि आप एक सिग्नल हैंडलर के रिटर्न वैल्यू के आधार पर कुछ क्रियाओं को रोक सकें।

contrib.comments ऐप ऐसा करता है, जो किसी रिसीवर को सिग्नल एक्शन को "रद्द" करने के लिए झूठा रिटर्न देता है। lines 111-120 देखें:

हालांकि, core Django code जो pre_delete, pre_save, आदि संकेतों को जारी करता है, इसमें कोई विशेष हैंडलिंग नहीं है। ये सभी सिग्नल रिसीवर को सूचित करते हैं कि कुछ हुआ है।

def on_delete(sender,**kwargs): 
    if not <some condition>: 
    raise Exception('Do not delete')#cancel the deletion 
# else continue with the deletion 
pre_delete.connect(on_delete,sender=MyModel) 

और देखने

def on_save(sender,**kwargs): 
    obj = kwargs['instance'] 
    try: 
    id = obj.pk 
    # find the file 
    original_file = sender.objects.get(pk=id) 
    # delete the original file before uploading a new file 
    except ... : 
    # oder exceptions 

    try: 
    original_file.file.delete() 
    except: 
    pass #not deleted 

pre_save.connect(on_save,sender=ModelWithFileUpload) 

संकेत में अपवाद स्थापना ब्रेक, जबकि जगह यह लागू किया गया था करने के लिए अपवाद लौटने() विधि निष्पादन को हटा देना चाहिए:

1

मैं एक छोटे से हैक वैकल्पिक हल की कोशिश करेंगे। आप केवल कुछ प्रकार के अपवाद को छोड़कर अपना स्वयं का अपवाद सबक्लास बना सकते हैं (आपको लगभग किसी भी तर्क के अलावा उपयोग नहीं करना चाहिए)।

+0

मैं यह नहीं करूँगा। हां यह कस्टम दृश्य के लिए काम करता है, लेकिन व्यवस्थापक के माध्यम से ऑब्जेक्ट को हटाने का प्रयास करने वाला कोई व्यक्ति ग़लत त्रुटि प्राप्त करेगा यदि उस अपवाद को उठाया गया हो और संभाला न जाए। – shadfc

+0

आप बिल्कुल सही हैं। जैसा कि मैंने कहा, यह बदसूरत हैक है। – thedk

+0

मुझे नहीं लगता कि यह सभी परिस्थितियों में एक हैक है। जब प्रयास हटाना केवल गलत परिस्थितियों में हो सकता है, तो अपवाद फेंकना सही प्रतिक्रिया की तरह लगता है। – Teekin

1

मुझे पता है कि मेरा जवाब थोड़ा देर हो गया है, लेकिन इस प्रश्न का दूसरा भाग बिल्कुल है जो मुझे कुछ दिनों पहले चाहिए था।

तो, सबसे पहली बात:

  1. वहाँ Django pre_delete संकेत का उपयोग कर रिकॉर्ड की एक हटाना बंद करने के लिए एक रास्ता है?

नहीं वास्तव में, thedk द्वारा प्रस्तावित एक को छोड़कर। और ईमानदारी से, कोई भी नहीं होना चाहिए। क्यूं कर? क्योंकि pre_delete किसी ऑब्जेक्ट को हटाने से पहले होने वाली किसी क्रिया के लिए है। यदि आप हटाने को रोकते हैं, तो यह अब pre_delete नहीं है (दुष्चक्र को नोटिस करें?)

  1. वहाँ है कि पहले मूल फ़ाइल को हटाने के लिए एक फ़ाइल को बदलने से पहले एक मॉडल के लिए कहने के लिए एक तरीका है?

हाँ, वहाँ है, और आप इसे काफी अधिकार मिल गया। मैंने एक और सामान्य कोड बनाया है, जो किसी भी मॉडल के लिए काम करेगा जिसमें फ़ाइल ऑब्जेक्ट्स संबंधित हैं (नीचे देखें)। हालांकि, आपको read why को फोरहैंड करना चाहिए यह व्यवहार Django 1.3 में हटा दिया गया था और देखें कि यह किसी भी तरह से आपके तर्क को प्रभावित करता है या नहीं। यह मुख्य रूप से संबंधित मॉडलों से रोलबैक और एक ही फ़ाइल के एकाधिक संदर्भों को कैसे संभालने से संबंधित है।

def delete_files_from_instance(instance, field_names): 
    for field_name in field_names: 
     field_value = getattr(instance, field_name, None) 
     if field_value: 
      if isinstance(field_value, File): 
       try: 
        os.remove(field_value.path) 
       except OSError: 
        pass 


@receiver(pre_delete) 
def on_delete(sender, instance, **kwargs): 
    # When an object is deleted, all associated files are also removed 
    delete_files_from_instance(instance, sender._meta.get_all_field_names()) 


@receiver(pre_save) 
def on_update(sender, instance, **kwargs): 
    # When an object is updated, if any media files are replaced, the old ones should be deleted. 
    from_fixture = 'raw' in kwargs and kwargs['raw'] # this prevents errors when loading files from fixtures 
    is_valid_app = sender._meta.app_label in VALID_APPS # Define what apps are targeted by your code 
    if is_valid_app and not from_fixture: 
     try: 
      old_instance = sender.objects.filter(pk=instance.id).first() 
      if old_instance and old_instance is not None: 
       delete_files_from_instance(old_instance, sender._meta.get_all_field_names()) 
     except LookupError: 
      pass 

कृपया ध्यान में रखना यह मानता है कि कि आपके हटाने/अद्यतन कार्रवाई सफल हो जाएगा। यदि यह विफल रहता है, तो आपने स्थायी रूप से एक फ़ाइल खो दी है।

एक बेहतर दृष्टिकोण संकेतों post_save/post_delete में फ़ाइल हटाने की संभाल करने के लिए, या एक क्रॉन जॉब जो समय समय पर जो अब डेटाबेस द्वारा दर्शाया जाता है सभी फाइलों को साफ बनाने के लिए किया जाएगा।

+0

रिकॉर्ड बनाने से पहले किसी तृतीय पक्ष सेवा से बात करने की आवश्यकता के मामले में एक अद्वितीय आईडी प्राप्त करने के लिए कहें, तो 'pre_save' या' pre_delete' सही जगह लगता है। आप कहां सिफारिश करेंगे? – surfer190

+0

चूंकि आपने "सृजन से पहले" कहा था, तो 'pre_save' सही जगह होना चाहिए। – AdelaN

+0

हां, लेकिन अगर सेवा विफल हो जाती है तो मैं मॉडल को सहेजना नहीं चाहता ... – surfer190

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