2011-03-19 14 views
9

मैं Django आवेदन के विकास कर रहा हूँ, और मैं इस तरह के एक मॉडल संरचनाबहुरूपता

class Animal(models.Model): 
    aul = models.ForeignKey(Aul) 
    age = models.IntegerField() 

    def __unicode__(self): 
     return u'Animal' 

class Sheep(Animal): 
    wool = models.IntegerField() 

    def __unicode__(self): 
     return u'Sheep' 

है और मैं टेम्पलेट animal_set और आउटपुट इस {{ animal }} की तरह हर वस्तु गुजरती हैं। यह पशु आउटपुट करता है, लेकिन मैंने भेड़ के प्रकार की वस्तुओं को बनाया और जानवरों की भेड़ की विधि __unicode__ का उपयोग करना चाहते हैं।

Django मॉडल में polymorphism काम करते हैं? मुझे कई जवाब मिल गए हैं, लेकिन मॉडल के अंदर लिखने के लिए कोड के स्निपेट हैं, लेकिन मुझे देशी समाधानों में दिलचस्पी है।

+0

[django-polymorphic] (https://github.com/chrisglass/django_polymorphic) देखें, जो इस उपयोग के मामले के लिए डिज़ाइन किया गया है। यह तब भी काम करता है जब मॉडल विदेशीकी, ManyToManyFields, आदि के माध्यम से लाया जाता है .. – vdboor

+0

ऐसा मत करो! : पी नीचे अपना ले देखें: http://stackoverflow.com/a/20353347/539490 – AJP

उत्तर

3

आप {{animal.sheep}} तक पहुंचकर सफल हो सकते हैं - मॉडल विरासत वह नहीं है जो आप सोचेंगे, उस कवर के तहत भारी मेटाक्लास मशीनरी है जो इस तरह की विरासत को एक अंतर्निहित OneToOneField संबंध में परिवर्तित करती है।

+0

पता नहीं क्यों यह उत्तर डाउनवॉट किया गया क्योंकि यह समस्या के बारे में सटीक है। हालांकि थोड़ा अपूर्ण, लेकिन अभी भी सटीक है। –

1

django-polymorphic-models नामक एक बहुत ही सरल django ऐप है जो आपको इसके साथ मदद करता है। यह आपको मॉडल पर downcast() विधि प्रदान करेगा जो आपके "बच्चे" ऑब्जेक्ट के साथ-साथ इन समस्याओं से निपटने के लिए एक विशेष क्वेरीसेट क्लास वापस कर देगा!

यह भी जानना बहुत उपयोगी हो सकता है कि बेस मॉडल की क्वेरीसेट पर select_related() का उपयोग करने से बच्चे की वस्तुएं भी मिल जाएंगी, जिन्हें OneToOneField के माध्यम से संदर्भित किया जाता है, जो कभी-कभी एक अच्छा प्रदर्शन बढ़ावा हो सकता है!

8

लेखन के समय, जैंगो नवीनतम संस्करण 1.2

था लेकिन यह काम करने के लिए कुछ अतिरिक्त तत्वों की जरूरत है।

आपको एक कस्टम मॉडल असाइन करने की आवश्यकता है। प्रत्येक पशु मॉडल के लिए प्रबंधक ऑब्जेक्ट जो अपनी कस्टम क्वेरीरी ऑब्जेक्ट को कॉल करेगा।

असल में, बजाय यदि आइटम के मॉडल Animal है या नहीं की जाँच करने के Animal उदाहरणों (यह आप क्या मिलता है), SubclassingQuerySet कॉल as_leaf_class() विधि लौटने की - अगर ऐसा है, तो बस इसे वापस, नहीं तो अपने मॉडल के संदर्भ में खोज करें। बस।

#models.py 
from django.db import models 
from django.contrib.contenttypes.models import ContentType 
from django.db.models.query import QuerySet 


class SubclassingQuerySet(QuerySet): 
    def __getitem__(self, k): 
     result = super(SubclassingQuerySet, self).__getitem__(k) 
     if isinstance(result, models.Model): 
      return result.as_leaf_class() 
     return result 

    def __iter__(self): 
     for item in super(SubclassingQuerySet, self).__iter__(): 
      yield item.as_leaf_class() 


class AnimalManager(models.Manager): 
    def get_query_set(self): # Use get_queryset for Django >= 1.6 
     return SubclassingQuerySet(self.model) 


class Animal(models.Model): 
    name = models.CharField(max_length=100) 
    content_type = models.ForeignKey(ContentType, editable=False, null=True) 
    objects = AnimalManager() 

    def __unicode__(self): 
     return "Animal: %s" % (self.name) 

    def save(self, *args, **kwargs): 
     if not self.content_type: 
      self.content_type = ContentType.objects.get_for_model(self.__class__) 
     super(Animal, self).save(*args, **kwargs) 

    def as_leaf_class(self): 
     content_type = self.content_type 
     model = content_type.model_class() 
     if model == Animal: 
      return self 
     return model.objects.get(id=self.id) 


class Sheep(Animal): 
    wool = models.IntegerField() 
    objects = AnimalManager() 

    def __unicode__(self): 
     return 'Sheep: %s' % (self.name) 

परीक्षण:

>>> from animals.models import * 
>>> Animal.objects.all() 
[<Sheep: Sheep: White sheep>, <Animal: Animal: Dog>] 
>>> s, d = Animal.objects.all() 
>>> str(s) 
'Sheep: White sheep' 
>>> str(d) 
'Animal: Dog' 
>>> 
+1

यह मुख्य रूप से djanogo-polymorphic-models करता है, लेकिन यह कार्यक्षमता को थोड़ा और अधिक सामान्य प्रदान करता है .... –

+0

मुझे लगता है कि as_leaf_class विधि हर बार डीबी को दबाएगी। मैंने जो किया वह कक्षा को सीधे स्वयं का उपयोग करके सेट करना है .__ class__ = model – Johan

+0

@johan कोड नहीं बदलता है। 2011 में, Django पूर्व 1.6 पर, 'get_query_set' सही बात थी। यदि आप आगंतुकों को सूचित करना चाहते हैं कि एक नाम बदल गया है, तो टिप्पणी में ऐसा करें। –

0

आप इस जवाब की जांच होनी चाहिए: https://stackoverflow.com/a/929982/684253

समाधान यह प्रस्ताव Django-बहुरूपी-मॉडल का उपयोग कर के समान है, जो पहले से ही @lazerscience द्वारा उल्लेख किया गया था। लेकिन मैं कहूंगा कि django-model-utils django-polymorphic से थोड़ा बेहतर दस्तावेज है, और लाइब्रेरी का उपयोग करना आसान है। "विरासत प्रबंधक" के तहत रीडेमे देखें: https://github.com/carljm/django-model-utils/#readme

1

मैं Django प्रॉक्सी मॉडल का उपयोग करने की अनुशंसा करता हूं, उदा। यदि आप बेस मॉडल पशु जो भेड़ और घोड़े से subclassed है आप का प्रयोग करेंगे:

class Animal(models.Model): 
    pass 

class Horse(Animal): 
    class Meta(Animal.Meta): 
     proxy = True 

class Sheep(Animal): 
    class Meta(Animal.Meta): 
     proxy = True 

इस के लिए what Proxy models are intended नहीं है, लेकिन मैं जब तक आप में मॉडल विशिष्ट डेटा भंडारण के लाभ की जरूरत है Django बहुरूपता उपयोग करने की अनुशंसा नहीं होता अलग टेबलयदि आपके पास सौ घोड़े के विशिष्ट गुण हैं जो डेटाबेस में संग्रहीत डिफ़ॉल्ट मान हैं, और उसके बाद केवल 2 घोड़े की वस्तुएं हैं, लेकिन दस लाख भेड़ें हैं, तो आपके पास दस लाख पंक्तियां हैं, जिनमें से प्रत्येक सौ घोड़े के विशिष्ट मूल्य हैं जिनकी आपको परवाह नहीं है के बारे में, लेकिन फिर यह केवल वास्तव में प्रासंगिक है यदि आपके पास पर्याप्त डिस्क स्थान नहीं है, जो असंभव है। जब बहुरूपता अच्छी तरह से काम करती है तो यह ठीक है, लेकिन जब यह दर्द नहीं होता है।

+0

आप माता-पिता (यानी एकल तालिका) विरासत (वांछित शामिल तालिका विरासत के विपरीत) का सुझाव दे रहे हैं, लेकिन आप नहीं जानते कि वास्तविक मॉडल वह है या केवल एक उदाहरण है। एसटीआई और जेटीआई के बीच एक अकादमिक बहस है। जब तक इसके विपरीत नहीं कहा जाता है तब तक आपको जेटीआई विकसित करने के कुशल तरीके के बारे में उसकी मदद करनी चाहिए। –

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