2010-07-09 8 views
13

"देखना" चाहूंगा जब एक Django मॉडल (.save()) पर कोई अपडेट/निर्माण किया जाता है, तो मैं "चरणबद्ध" और तुलना करने में सक्षम होना चाहता हूं कुछ खास गुण जो उन्हें पहले सेट किए गए थे (यदि वे पहले से मौजूद थे)।Django: मॉडल को अपडेट करने से पहले, मैं अपने पिछले गुणों को

मैं सोच रहा हूँ सिग्नल पूर्व सहेजें, एक .objects.get(instance.id) कर मूल मॉडल के लिए एक नज़र-अप के साथ, लेकिन यह बेकार लगता है। साथ ही, क्या सत्यापन पहले से ही pre_save() में हुआ है?

उत्तर

7

model validation के बारे में:

ध्यान दें कि full_clean() स्वचालित रूप से कहा जा नहीं होगा जब आप अपने मॉडल के सेव() विधि

फिर कहते हैं, pre-save signal के बारे में, ध्यान दें कि आप उदाहरण मिल यह सहेजा जा रहा है संदेश के साथ पैरामीटर के रूप में भेजा गया है। चूंकि आपके मॉडल का पूर्व संस्करण केवल डेटाबेस में मौजूद है, मुझे नहीं लगता कि आप गुणों के पिछले मूल्य कहां प्राप्त कर सकते हैं ...

आप यह नहीं बताते कि आप ऐसा क्यों करना चाहते हैं, इसलिए यह कठिन है कहने के लिए है, लेकिन अन्य समाधान मैं अभी सोच रहा हूँ:

* defining a custom signal that is sent everytime the attributes you are interested in are modified... This signal would then send two arguments : new value, old value 
* perform the check directly when setting the attributes 

आप अधिक विवरण देते हैं, तो यह आसान हो सकता है ...

संपादित करें:

यह सही है ... तो आप एक कस्टम 'foo_has_updated' उत्सर्जित करते हैं, आप सुनिश्चित नहीं होंगे कि संशोधन सहेजा गया है।

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

* With pre-save, you would be able to pre-process the data, but the saving operation might fail 
* With post-save, you would be sure that the data has been saved. 

अपने चर कैशिंग इस तरह किया जा सकता है:

class CachedModel(models.Model): 
    cached_vars = [var1, var2, varN] 
    def __init__(self, *args, **kwargs): 
     super(CachedModel, self).__init__(*args, **kwargs) 
     self.var_cache = {} 
     for var in self.cached_vars: 
      self.var_cache[var] = copy.copy(getattr(self, var)) 

या कुछ इस तरह ... फिर, अपने संकेत हैंडलर में:

def post_save_handler(sender, **kwargs): 
    instance = kwargs["instance"] 
    [(instance.var_cache[var], getattr(instance, var)) for var in instance.cached_var] 
    #[(<initial value>, <saved value>) 

और तुम मिल गया है कि तुम क्या जरूरत (मुझे लगता है)!!!

+0

आपके उत्तर के लिए धन्यवाद। विशेष रूप से, और फिर भी काफी सामान्य रूप से, मैं जानना चाहता हूं कि एक विशेष क्षेत्र (उदाहरण के लिए एक विकल्प क्षेत्र) बदल दिया गया है। आगे बढ़ते हुए, जैसा कि आपने कहा था, मैं ऐसा करना चाहता हूं - ऐसा होने पर कस्टम सिग्नल छोड़ दें। इस प्रकार मेरे प्रश्न पर वापस जा रहा है - जब कोई मॉडल अपडेट किया जाता है, तो मैं इस सिग्नल को भेजने के लिए अपने पिछले मानों की तुलना कैसे कर सकता हूं? (यदि ऑब्जेक्ट को post_save से पहले सहेजने की गारंटी नहीं है, तो यह सत्यापित किए बिना foo_has_updated सिग्नल को निकालने का अधिकार प्रतीत नहीं होता है ... लेकिन यह एक और सवाल है)। –

0

आप सहेजने से पहले डेटाबेस में वर्तमान में संग्रहीत मूल्यों के लिए पूछ सकते हैं। मैंने इसे केवल बदले गए मानों को लॉग करने के लिए किया है, लेकिन हर बार जब आप सहेजते हैं तो यह एक और डेटाबेस क्वेरी का कारण बनता है।

0

जबकि मैं Sébastien Piquemal's answer की बहुत स्वीकृति देता हूं, अंततः मैं pre_save और post_save सिग्नल दोनों का उपयोग करके समाप्त हुआ। __init__() अधिभावी के बजाय, मैं pre_save में बहुत कुछ इसी तरह करते हैं, और उसके बाद जाँच/post_save में मूल्यों की तुलना और वहाँ से एक कस्टम संकेत फेंकना विशेष शर्तें पूरी कर रहे हैं।

मुझे लगता है कि मैं अभी भी अपने जवाब को स्वीकार करेंगे, उस पर व्यतीत समय के लिए। मुझे नहीं है जहाँ हम बहुत अलग कर रहे हैं, को छोड़कर मैं एक संकेत में मेरे काम कर रहा हूँ और वह आरंभीकरण के दौरान यह कर रहा है। गुण के साथ चारों ओर खेलने:

2

यहाँ मेरी विचार है।

class Foo(models.Model): 
    name = models.CharField() 

इसके बजाय, नाम बदलने अपने क्षेत्र (अगर यह पहली बार आप इस कर रहे हैं आप एक प्रवास की जरूरत नहीं होगी) और:

class Foo(models.Model): 
    _name = models.CharField() 

    @property 
    def name(self): 
     return self._name 

    @name.setter 
    def name(self, new_value): 
     if not getattr(self, '_initial_name', False): 
      self._initial_name = self._name 

     if new_value != self._initial_name: 
      self._name_changed = True 
     else: 
      self._name_changed = False 

     self._name = new_value 

आप इस वर्ग है कहो

हमने आपके Foo उदाहरणों में दो विशेषताओं को जोड़ा: '_initial_name' और '_name_changed' और एक संपत्ति: 'name'। ये मॉडल फ़ील्ड नहीं हैं और डेटाबेस पर कभी भी सहेजे नहीं जाएंगे। साथ ही, आपको '_name' फ़ील्ड के साथ अब तक गड़बड़ नहीं करना पड़ेगा जब तक कि 'नाम' संपत्ति सब कुछ का ख्याल रखे।

def handle_pre_save(sender, **kwargs): 
    foo = kwargs['instance'] 
    if getattr(foo, '_name_changed', False): 
     log.debug("foo changed its name from '%s' to '%s'", 
        foo._initial_name, foo.name) 
0

आप pre_save संकेत का उपयोग करें और साथ डाटाबेस रिकॉर्ड (पुराना संस्करण) की तुलना कर सकते हैं:

अब, अपने 'pre_save' या 'post_save' सिग्नल हैंडलर क्या है बदल की जांच कर सकते हैं उदाहरण रिकॉर्ड (अद्यतन, लेकिन डीबी संस्करण में सहेजा नहीं गया)। एक pre_save समारोह में

class Person(models.Model): 
    Name = models.CharField(max_length=200) 

आप डाटाबेस संस्करण के साथ उदाहरण के संस्करण तुलना कर सकते हैं:

उदाहरण के रूप में इस तरह के एक मॉडल है।

def check_person_before_saving(sender, **kwargs): 
    person_instance = kwargs['instance'] 
    if person_instance.id: 
     # you are saving a Person that is already on the db 
     # now you can get the db old version of Person before the updating 

     # you should wrap this code on a try/except (just in case) 
     person_db = Person.objects.get(id=person_instance.id) 

     # do your compares between person_db and person_instance 
     ... 

# connect the signal to the function. You can use a decorator if you prefer 
pre_save.connect(check_person_before_saving, sender=Person) 
संबंधित मुद्दे