2009-09-14 14 views
12

मेरी डीजेंगो साइट में मेरे पास दो ऐप्स, ब्लॉग और लिंक हैं। ब्लॉग में एक मॉडल ब्लॉगपोस्ट है, और लिंक में एक मॉडल लिंक है। इन दो चीजों के बीच कई रिश्तों में से एक होना चाहिए। प्रति ब्लॉगपोस्ट के कई लिंक हैं, लेकिन प्रत्येक लिंक में एक और केवल एक ब्लॉग पोस्ट है। सरल जवाब लिंक मॉडल में एक विदेशीकी को ब्लॉगपोस्ट में रखना है।एक पुन: प्रयोज्य Django ऐप में एक विदेशी कुंजी मॉडल कैसे करें?

यह सब ठीक है और अच्छा है, हालांकि एक समस्या है। मैं लिंक ऐप को पुन: प्रयोज्य बनाना चाहता हूं। मैं नहीं चाहता कि यह ब्लॉग ऐप पर निर्भर करे। मैं इसे अन्य साइटों में फिर से उपयोग करने में सक्षम होना चाहता हूं और शायद अन्य गैर-ब्लॉगपोस्ट ऐप्स और मॉडल के साथ लिंक जोड़ना चाहता हूं।

एक सामान्य विदेशी कुंजी ऐसा लगता है कि यह उत्तर हो सकता है, लेकिन वास्तव में नहीं। मैं नहीं चाहता कि लिंक मेरी साइट के किसी भी मॉडल से जुड़ सकें। बस एक जिसे मैं स्पष्ट रूप से निर्दिष्ट करता हूं। और मुझे पूर्व अनुभव से पता है कि डेटाबेस उपयोग के संदर्भ में सामान्य विदेशी कुंजी का उपयोग करने में समस्याएं हो सकती हैं क्योंकि आप नियमित विदेशी कुंजी के साथ एक सामान्य विदेशी कुंजी पर चयन_संबंधित नहीं कर सकते हैं।

इस रिश्ते को मॉडल करने के लिए "सही" तरीका क्या है?

उत्तर

22

से यदि आपको लगता है लिंक एप्लिकेशन को हमेशा एक ही ऐप्लिकेशन को इंगित करेंगे तो एक दृष्टिकोण एक स्ट्रिंग एक वर्ग संदर्भ की बजाय आवेदन लेबल युक्त के रूप में विदेशी मॉडल का नाम पारित करने के लिए किया जाएगा (Django docs explanation) ।

दूसरे शब्दों में, के बजाय:

class Link(models.Model): 
    blog_post = models.ForeignKey(BlogPost) 

कार्य करें:

from django.conf import setings 
class Link(models.Model): 
    link_model = models.ForeignKey(settings.LINK_MODEL) 

और अपने settings.py में:

LINK_MODEL = 'someproject.somemodel' 
+0

मैं भूल गया था कि django आपको इसके लिए स्ट्रिंग मॉडल नामों का उपयोग करने देता है। +1 – SingleNegationElimination

+0

ओह वाह, सेटिंग्स का उपयोग करने के लिए महान विचार। धन्यवाद! – Apreche

+0

ध्यान दें कि इस दृष्टिकोण को पुन: प्रयोज्य ऐप स्तर पर नए माइग्रेशन बनाने की आवश्यकता होगी। – Bula

0

शायद आपको किसी मॉडल से लिंक करने के लिए सामग्री प्रकार ऐप का उपयोग करने की आवश्यकता है। इसके बाद आप अपने ऐप को सेटिंग्स को जांचने के लिए कुछ अतिरिक्त जांच करने के लिए व्यवस्था कर सकते हैं ताकि यह सीमित किया जा सके कि कौन से सामग्री प्रकार इसे स्वीकार करेंगे या सुझाव देंगे।

1

मुझे लगता है कि टोकनमैकगुई सही रास्ते पर है। मैं देखता हूं कि कैसे django-tagging सामग्री प्रकार, सामान्य ऑब्जेक्ट_आईडी, and generic.py का उपयोग कर एक समान सामान्य संबंध को संभालता है। models.py

class TaggedItem(models.Model): 
    """ 
    Holds the relationship between a tag and the item being tagged. 
    """ 
    tag   = models.ForeignKey(Tag, verbose_name=_('tag'), related_name='items') 
    content_type = models.ForeignKey(ContentType, verbose_name=_('content type')) 
    object_id = models.PositiveIntegerField(_('object id'), db_index=True) 
    object  = generic.GenericForeignKey('content_type', 'object_id') 

    objects = TaggedItemManager() 

    class Meta: 
     # Enforce unique tag association per object 
     unique_together = (('tag', 'content_type', 'object_id'),) 
     verbose_name = _('tagged item') 
     verbose_name_plural = _('tagged items') 
+0

हाँ, मैंने विशेष रूप से कहा था कि मैं जीएफके का उपयोग नहीं करना चाहता था क्योंकि तब मैं blogpost.objects.all()। select_related ('link') या समकक्ष नहीं कर सकता। – Apreche

0

मैं सामान्य संबंधों के साथ जाना चाहते हैं। आप select_related जैसे कुछ कर सकते हैं, इसे केवल कुछ अतिरिक्त काम की आवश्यकता है। लेकिन मुझे लगता है कि यह इसके लायक है।

एक सामान्य select_related जैसी कार्यप्रणाली के लिए संभव समाधान:

http://bitbucket.org/kmike/django-generic-images/src/tip/generic_utils/managers.py

(GenericInjector प्रबंधक को देखो और विधि inject_to है)

0

यह सवाल और वान गेल answer सवाल, कैसे करने के लिए मुझे नेतृत्व मॉडल में क्यू ऑब्जेक्ट्स के माध्यम से इसे परिभाषित करने की आवश्यकता के बिना जीएफके के लिए सामग्री प्रकार सीमित करने के लिए यह संभव हो सकता है, इसलिए यह पूरी तरह से उपयोग किया जा सकता है

समाधान

  • django.db.models पर आधारित है।get_model
  • और अंतर्निहित eval, जो settings.TAGGING_ALLOWED से क्यू-ऑब्जेक्ट का मूल्यांकन करता है। यह व्यवस्थापक इंटरफ़ेस में उपयोग के लिए आवश्यक है

मेरे कोड काफी किसी न किसी तरह है और पूरी तरह से परीक्षण नहीं

settings.py

TAGGING_ALLOWED=('myapp.modela', 'myapp.modelb') 

models.py:

from django.db import models 
from django.db.models import Q 
from django.contrib.contenttypes.models import ContentType 
from django.contrib.contenttypes import generic 
from django.db.models import get_model 
from django.conf import settings as s 
from django.db import IntegrityError 

TAGABLE = [get_model(i.split('.')[0],i.split('.')[1]) 
     for i in s.TAGGING_ALLOWED if type(i) is type('')] 
print TAGABLE 

TAGABLE_Q = eval('|'.join(
    ["Q(name='%s', app_label='%s')"%(
     i.split('.')[1],i.split('.')[0]) for i in s.TAGGING_ALLOWED 
    ] 
)) 

class TaggedItem(models.Model): 
    content_type = models.ForeignKey(ContentType, 
        limit_choices_to = TAGABLE_Q)        
    object_id = models.PositiveIntegerField() 
    content_object = generic.GenericForeignKey('content_type', 'object_id') 

    def save(self, force_insert=False, force_update=False): 
     if self.content_object and not type(
      self.content_object) in TAGABLE: 
      raise IntegrityError(
       'ContentType %s not allowed'%(
       type(kwargs['instance'].content_object))) 
     super(TaggedItem,self).save(force_insert, force_update) 

from django.db.models.signals import post_init 
def post_init_action(sender, **kwargs): 
    if kwargs['instance'].content_object and not type(
     kwargs['instance'].content_object) in TAGABLE: 
     raise IntegrityError(
      'ContentType %s not allowed'%(
      type(kwargs['instance'].content_object))) 

post_init.connect(post_init_action, sender= TaggedItem) 

बेशक कंटेंट टाइप-फ्रेमवर्क की सीमाएं इस समाधान को प्रभावित करती हैं

इस को हल करने के
# This will fail 
>>> TaggedItem.objects.filter(content_object=a) 
# This will also fail 
>>> TaggedItem.objects.get(content_object=a) 
1

anoher तरीका है कैसे django-mptt है इस: एक पुन: प्रयोज्य एप्लिकेशन (MPTTModel) में केवल एक सार मॉडल को परिभाषित, और स्वयं के लिए कुछ क्षेत्रों (मूल = ForeignKey परिभाषित करने के साथ यह वारिस की आवश्यकता होती है, या जो कुछ भी अपने अनुप्रयोग USECASE आवश्यकता होगी)

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