Django के model.save () को full_clean () क्यों नहीं कहते हैं?


150

अगर किसी को पता है कि क्या कोई अच्छा कारण है तो मुझे बहुत उत्सुकता है अगर django का orm किसी मॉडल पर 'full_clean' नहीं कहता है जब तक कि इसे मॉडल फॉर्म के भाग के रूप में सहेजा नहीं जा रहा है।

ध्यान दें कि जब आप अपने मॉडल के सेव () विधि को कहते हैं तो full_clean () स्वचालित रूप से नहीं कहा जाएगा। जब आप अपने स्वयं के बनाए गए मॉडल के लिए एक-चरण मॉडल सत्यापन चलाना चाहते हैं, तो आपको इसे मैन्युअल रूप से कॉल करना होगा। django का पूर्ण स्वच्छ डॉक्टर

(नोट: Django 1.6 के लिए अद्यतन उद्धरण ... पिछले django डॉक्स के रूप में अच्छी तरह से ModelForms के बारे में एक चेतावनी थी।)

क्या अच्छे कारण हैं कि लोग इस व्यवहार को क्यों नहीं चाहेंगे? मुझे लगता है कि यदि आपने किसी मॉडल में सत्यापन जोड़ने के लिए समय लिया है, तो आप चाहते हैं कि मॉडल सहेजे जाने पर हर बार सत्यापन चले।

मुझे पता है कि सब कुछ ठीक से काम करने के लिए कैसे मिलता है, मैं बस एक स्पष्टीकरण की तलाश कर रहा हूं।


11
इस सवाल के लिए बहुत-बहुत धन्यवाद, इसने मुझे दीवार के खिलाफ अपना सिर पीटने से ज्यादा समय तक रोक दिया। मैंने एक मिश्रण बनाया जो दूसरों की मदद कर सकता है। जिस्ट की
Glarrain

और मैं अंत में pre_saveहुक को पकड़ने के लिए सिग्नल का उपयोग करता हूं और full_cleanसभी पकड़े गए मॉडल पर करता हूं ।
अल्फ्रेड हुआंग

जवाबों:


59

AFAIK, यह पश्चगामी संगतता के कारण है। मॉडलफार्म के साथ समस्याओं को भी छोड़ दिया है, बाहर के क्षेत्रों के साथ, डिफ़ॉल्ट मान के साथ मॉडल, पूर्व_ (संकेत), आदि।

आपको जिन स्रोतों से इंट्रस्ट किया जा सकता है:


3
दूसरे संदर्भ से सबसे अधिक उपयोगी अंश (IMHO): "एक" स्वचालित "सत्यापन विकल्प विकसित करना जो दोनों सरल है जो वास्तव में उपयोगी हो और सभी किनारे के मामलों को संभालने के लिए पर्याप्त मजबूत हो - यदि यह संभव है - तो इससे भी अधिक 1.2 टाइमफ्रेम पर पूरा किया जा सकता है। इसलिए, अब के लिए, Django के पास ऐसी कोई चीज नहीं है, और 1.2 में नहीं होगी। अगर आपको लगता है कि आप इसे 1.3 के लिए काम कर सकते हैं, तो आपका सबसे अच्छा दांव काम करना है। प्रस्ताव, कम से कम कुछ नमूना कोड सहित, आप इसे सरल और मजबूत दोनों कैसे रखेंगे, इसकी व्याख्या के साथ। "
जोश

30

संगतता पर विचार करने के कारण, सेव पर ऑटो क्लीन django कर्नेल में सक्षम नहीं है।

यदि हम एक नई परियोजना शुरू कर रहे हैं और चाहते हैं कि saveमॉडल पर डिफ़ॉल्ट विधि स्वचालित रूप से साफ हो जाए, तो हम प्रत्येक मॉडल को सहेजने से पहले स्वच्छ करने के लिए निम्न संकेत का उपयोग कर सकते हैं।

from django.dispatch import receiver
from django.db.models.signals import pre_save, post_save

@receiver(pre_save)
def pre_save_handler(sender, instance, *args, **kwargs):
    instance.full_clean()

2
कुछ बेसमॉडल (जो अन्य सभी से वारिस होंगे) को बचाने के तरीके को ओवरराइड करने से बेहतर (या बदतर) क्यों है, पहले full_clean को कॉल करें, फिर सुपर () को कॉल करें?
21

7
मुझे इस दृष्टिकोण के साथ दो समस्याएं दिखाई देती हैं 1) मॉडलफार्म के फुल_क्लीन () के रूप में दो बार कहा जाएगा: फॉर्म द्वारा और सिग्नल 2) यदि फॉर्म कुछ क्षेत्रों को बाहर करता है, तो वे अभी भी सिग्नल द्वारा मान्य होंगे।
mehmet

1
@mehmet तो आप इन if send == somemodel, then exclude some fieldsमें जोड़ सकते हैंpre_save_handler
Simin Jie

4
जो लोग इस दृष्टिकोण का उपयोग या विचार कर रहे हैं, उनके लिए: ध्यान रखें कि यह दृष्टिकोण आधिकारिक रूप से Django द्वारा समर्थित नहीं है और भविष्य में समर्थित नहीं होगा (Django बग ट्रैकर में यह टिप्पणी देखें: code.djangoproject.com/ticket/ 29655 # टिप्पणी: 3 ), इसलिए यदि आप सभी मॉडलों के लिए सत्यापन सक्षम करते हैं, तो आपको कुछ खामियों पर रोक लगाने की संभावना है जैसे प्रमाणीकरण रोकना काम करना ( code.djangoproject.com/ticket/29655 )। आपको ऐसी समस्याओं से खुद ही निपटना होगा। हालांकि, वहाँ कोई बेहतर दृष्टिकोण है।
एवगेनी ए।

2
Django 2.2.3 के रूप में, यह मूल प्रमाणीकरण प्रणाली के साथ एक समस्या का कारण बनता है। आपको ए ValidationError: Session with this Session key already exists। इससे बचने के लिए, आपको sender in list_of_model_classesDjango के डिफ़ॉल्ट विशेषाधिकार मॉडल को ओवरराइड करने से रोकने के लिए एक if-statement जोड़ने की आवश्यकता है । परिभाषित करें list_of_model_classesकि आप चुनते हैं
Addison Klinke

15

full_cleanविधि को कॉल करने का सबसे सरल तरीका सिर्फ saveआपके में विधि को ओवरराइड करना है model:

def save(self, *args, **kwargs):
    self.full_clean()
    return super(YourModel, self).save(*args, **kwargs)

सिग्नल का उपयोग करने से बेहतर (या बदतर) क्यों है?
21

6
मुझे इस दृष्टिकोण के साथ दो समस्याएं दिखती हैं 1) मॉडलफार्म के फुल_क्लीन () के रूप में दो बार बुलाया जाएगा: फॉर्म द्वारा और सेव 2) यदि फॉर्म कुछ क्षेत्रों को बाहर करता है, तो वे अभी भी सेव द्वारा मान्य होंगे।
mehmet

3

रिसीवर घोषित करने वाले कोड का एक टुकड़ा डालने के बजाय, हम एक ऐप को INSTALLED_APPSसेक्शन के रूप में उपयोग कर सकते हैंsettings.py

INSTALLED_APPS = [
    # ...
    'django_fullclean',
    # your apps here,
]

इससे पहले, आपको django-fullcleanPyPI का उपयोग करके इंस्टॉल करना पड़ सकता है:

pip install django-fullclean

13
आप स्वयं इन पंक्तियों को लिखने के बजाय कोडpip install की 4 पंक्तियों के साथ कुछ एप्लिकेशन क्यों डालेंगे ( स्रोत कोड की जाँच करें )?
डेविड डी।

एक और पुस्तकालय जो मैंने स्वयं आजमाया नहीं है: github.com/danielgatis/django-smart-save
फ़्लिम

2

यदि आपके पास एक मॉडल है जिसे आप सुनिश्चित करना चाहते हैं कि आपके पास कम से कम एक एफके संबंध है, और आप इसका उपयोग नहीं करना चाहते हैं null=Falseक्योंकि इसके लिए डिफ़ॉल्ट एफके (जो कि कचरा डेटा होगा) सेट करने की आवश्यकता होती है, जो सबसे अच्छा तरीका है, मैं उसके साथ आया हूं। कस्टम .clean()और .save()विधियों को जोड़ने के लिए । .clean()सत्यापन त्रुटि उठाता है, और .save()क्लीन कॉल करता है। इस तरह अखंडता को रूपों से और अन्य कॉलिंग कोड, कमांड लाइन और परीक्षणों से लागू किया जाता है। इसके बिना, एक परीक्षण लिखने का कोई तरीका नहीं है (AFAICT) यह सुनिश्चित करता है कि एक मॉडल का विशेष रूप से चुने गए (डिफ़ॉल्ट नहीं) अन्य मॉडल से एफके संबंध है।

class Payer(models.Model):

    name = models.CharField(blank=True, max_length=100)
    # Nullable, but will enforce FK in clean/save:
    payer_group = models.ForeignKey(PayerGroup, null=True, blank=True,)

    def clean(self):
        # Ensure every Payer is in a PayerGroup (but only via forms)
        if not self.payer_group:
            raise ValidationError(
                {'payer_group': 'Each Payer must belong to a PayerGroup.'})

    def save(self, *args, **kwargs):
        self.full_clean()
        return super().save(*args, **kwargs)

    def __str__(self):
        return self.name

1

@Alfred हुआंग के उत्तर और उस पर कॉमेन्ट पर टिप्पणी। मौजूदा मॉड्यूल (मॉडेलस्टो) में कक्षाओं की सूची को परिभाषित करके और प्री_सैव हुक में इसके खिलाफ जांच करके एक ऐप को प्री_सैव हुक को बंद किया जा सकता है:

CUSTOM_CLASSES = [obj for name, obj in
        inspect.getmembers(sys.modules[__name__])
        if inspect.isclass(obj)]

@receiver(pre_save)
def pre_save_handler(sender, instance, **kwargs):
    if type(instance) in CUSTOM_CLASSES:
        instance.full_clean()
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.