Django - Model.create () विधि को ओवरराइड करना?


89

Django डॉक्स केवल ओवरराइड करने के लिए उदाहरण सूचीबद्ध save()और delete()। हालाँकि, मैं अपने मॉडल के लिए कुछ अतिरिक्त प्रसंस्करण को केवल तब ही परिभाषित करना चाहूंगा जब वे बनाए जाएंगे । रेल से परिचित किसी के लिए, यह एक :before_createफ़िल्टर बनाने के बराबर होगा । क्या यह संभव है?

जवाबों:


164

ओवरराइडिंग के __init__()कारण कोड को निष्पादित किया जाएगा जब भी वस्तु के अजगर प्रतिनिधित्व को त्वरित किया जाता है। मुझे पता नहीं है, लेकिन एक :before_createdफिल्टर मुझे लगता है जैसे यह कोड निष्पादित करने के लिए है जब ऑब्जेक्ट डेटाबेस में बनाया जाता है। यदि आप डेटाबेस में कोई नया ऑब्जेक्ट बनाते समय कोड निष्पादित करना चाहते हैं, तो आपको यह देखना चाहिए save()कि ऑब्जेक्ट में कोई pkविशेषता है या नहीं। कोड कुछ इस तरह दिखेगा:

def save(self, *args, **kwargs):
    if not self.pk:
        # This code only happens if the objects is
        # not in the database yet. Otherwise it would
        # have pk
    super(MyModel, self).save(*args, **kwargs)

7
मुझे वास्तव में संकेतों का उपयोग करके एक समाधान मिला है: docs.djangoproject.com/en/dev/topics/signals (पूर्व_ संकेत, विशेष रूप से)। हालाँकि, यह एक बहुत अधिक व्यावहारिक समाधान प्रतीत होता है। बहुत बहुत धन्यवाद।
ग्राउंड

4
मेरा मानना ​​है कि आप प्रबंधक विधि को ओवरराइड करने का मतलब है create? यह एक दिलचस्प समाधान है, लेकिन यह उन मामलों में काम नहीं करेगा जब ऑब्जेक्ट का उपयोग किया जा रहा है Object(**kwargs).save()या उस पर कोई अन्य भिन्नता है।
जच

4
मुझे नहीं लगता कि यह कोई हैक है। यह आधिकारिक समाधानों में से एक है।
लेस

6
यह नहीं होना चाहिए super(MyModel, self).save(*args, **kwargs)?
मार्क चकेरियन

1
हो सकता self.pkहै कि वस्तु को नया बनाया जा रहा है या सिर्फ अपडेट हो रहा है या नहीं, इसकी जांच करना सबसे अच्छा विकल्प नहीं है। कभी-कभी आप निर्माण समय में ऑब्जेक्ट आईडी प्रदान करते हैं (जैसे एक अनुकूलित गैर-डेटाबेस जनरेट किया गया मान KSUID), और यह इस खंड को कभी भी निष्पादित नहीं करेगा ... self._state.addingयदि यह पहली बार बचत हो रहा है या सिर्फ अपडेट कर रहा है, तो यह सुनिश्चित करने के लिए मूल्य है उन मामलों में मदद करता है।
शाहीनवाद

22

यह पुराना है, एक स्वीकृत उत्तर है जो काम करता है (ज़ैच का), और एक अधिक मुहावरेदार भी (माइकल बाइलेस्ट्रा का), लेकिन चूंकि यह अभी भी Google पर पहला परिणाम है जिसे ज्यादातर लोग देखते हैं, मुझे लगता है कि हमें और अधिक सर्वोत्तम प्रथाओं की आवश्यकता है- django यहाँ शैली उत्तर :

from django.db.models.signals import post_save

class MyModel(models.Model):
    # ...
    @classmethod
    def post_create(cls, sender, instance, created, *args, **kwargs):
        if not created:
            return
        # ...what needs to happen on create

post_save.connect(MyModel.post_create, sender=MyModel)

मुद्दा यह है:

  1. संकेतों का उपयोग करें ( आधिकारिक डॉक्स में यहां पढ़ें )
  2. अच्छे नेमस्पेसिंग के लिए एक विधि का उपयोग करें (यदि यह समझ में आता है) ... और मैंने @classmethodइसके बजाय इसे चिह्नित किया है @staticmethodक्योंकि सबसे अधिक संभावना है कि आपको कोड में स्थिर वर्ग के सदस्यों को संदर्भित करने की आवश्यकता होगी।

यहां तक ​​कि क्लीनर होगा यदि कोर Django एक वास्तविक post_createसंकेत होगा। (एक विधि के व्यवहार को बदलने के लिए यदि आपको बूलियन आर्ग पास करने की आवश्यकता है, तो इमोहो, जो कि 2 विधियाँ होनी चाहिए।)


22

पोस्ट_सैव सिग्नल बनाने का एक उदाहरण ( http://djangosnippets.org/snippets/500/ से )

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

@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
    """Create a matching profile whenever a user object is created."""
    if created: 
        profile, new = UserProfile.objects.get_or_create(user=instance)

यहां इस बात पर एक विचार-विमर्श किया गया है कि क्या संकेतों या कस्टम सेव विधियों का उपयोग करना सबसे अच्छा है https://web.archive.org/web/20120815022107/http://www.martin-geber.com/thought/2007/10/29/ Django-संकेतों-बनाम-कस्टम बचाने-विधि /

मेरी राय में इस कार्य के लिए संकेतों का उपयोग करना अधिक मजबूत, पढ़ने में आसान लेकिन लंबा है।


ऑब्जेक्ट इंटर्नल के साथ गड़बड़ करने के बजाय यह पसंदीदा तरीका है, हालांकि, यदि आप प्रश्न में मॉडल में संशोधन करते हैं, और उपरोक्त उदाहरण में केवल एक और निर्माण नहीं करते हैंinstance.save() , तो कॉल करना न भूलें । इसलिए इस मामले में, एक प्रदर्शन दंड भी है क्योंकि डेटाबेस में एक INSERT और एक अद्यतन क्वेरी होगी।
माइक शुल्टज

कस्टम बनाम कस्टम सेव के तरीकों का लिंक टूट गया है।
Sander Vanden Hautte

18

शाब्दिक रूप से प्रश्न का उत्तर देने के लिए, createमॉडल के प्रबंधक में विधि Django में नई वस्तुओं को बनाने का एक मानक तरीका है। ओवरराइड करने के लिए, कुछ ऐसा करें

from django.db import models

class MyModelManager(models.Manager):
    def create(self, **obj_data):
        # Do some extra stuff here on the submitted data before saving...
        # For example...
        obj_data['my_field'] = my_computed_value(obj_data['my_other_field'])

        # Now call the super method which does the actual creation
        return super().create(**obj_data) # Python 3 syntax!!

class MyModel(models.model):
    # An example model
    my_field = models.CharField(max_length=250)
    my_other_field = models.CharField(max_length=250)

    objects = MyModelManager()

इस उदाहरण में, मैं createवास्तव में निर्मित होने से पहले कुछ अतिरिक्त प्रसंस्करण करने के लिए प्रबंधक की विधि विधि को ओवरराइड कर रहा हूं ।

नोट: कोड की तरह

my_new_instance = MyModel.objects.create(my_field='my_field value')

इस संशोधित createविधि को क्रियान्वित करेगा , लेकिन कोड की तरह

my_new_unsaved_instance = MyModel(my_field='my_field value')

नहीं होगा।


3

ओवरराइडिंग __init__()आपको मॉडल के त्वरित होने पर कोड निष्पादित करने की अनुमति देगा। माता-पिता को कॉल करना न भूलें __init__()


आह हाँ यह जवाब था। पता नहीं कैसे मैंने इसे अनदेखा कर दिया। धन्यवाद इग्नासियो।
ग्राउंड


1

पसंदीदा उत्तर सही है लेकिन यह बताने के लिए कि ऑब्जेक्ट बनाया जा रहा है या नहीं यह परीक्षण काम नहीं करता है यदि आपका मॉडल UUIDModel से प्राप्त होता है। पीके क्षेत्र में पहले से ही एक मूल्य होगा।

इस मामले में, आप यह कर सकते हैं:

already_created = MyModel.objects.filter(pk=self.pk).exists()

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.