मान लें कि मेरे पास Box
एक GenericForeignKey
है जो Apple
उदाहरण या Chocolate
उदाहरण के लिए इंगित करता है। Apple
और Chocolate
बदले में, क्रमशः Farm
और Factory
पर विदेशीकेज़ हैं। मैं Box
es की एक सूची प्रदर्शित करना चाहता हूं, जिसके लिए मुझे Farm
और Factory
तक पहुंचने की आवश्यकता है। मैं इसे जितना संभव हो उतने डीबी प्रश्नों में कर सकता हूं?django: जेनेरिक फोरिनेकी
मिनिमल उदाहराणदर्शक उदाहरण:
class Farm(Model):
...
class Apple(Model):
farm = ForeignKey(Farm)
...
class Factory(Model):
...
class Chocolate(Model):
factory = ForeignKey(Factory)
...
class Box(Model)
content_type = ForeignKey(ContentType)
object_id = PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
...
def __unicode__(self):
if self.content_type == ContentType.objects.get_for_model(Apple):
apple = self.content_object
return "Apple {} from Farm {}".format(apple, apple.farm)
elif self.content_type == ContentType.objects.get_for_model(Chocolate):
chocolate = self.content_object
return "Chocolate {} from Factory {}".format(chocolate, chocolate.factory)
यहाँ कुछ चीजें मैंने कोशिश कर रहे हैं। इन सभी उदाहरणों में, एन बॉक्स की संख्या है। क्वेरी गिनती मानती है कि ContentType
एस Apple
और Chocolate
के लिए पहले से ही कैश किया गया है, इसलिए get_for_model()
कॉल डीबी को हिट नहीं करते हैं।
1) अनुभवहीन:
print [box for box in Box.objects.all()]
यह (बक्से लाने करता है) + एन (Apple या प्रत्येक बॉक्स के लिए चॉकलेट) + एन (प्रत्येक एप्पल के लिए फार्म लाने और लाने प्रत्येक चॉकलेट के लिए फैक्टरी) प्रश्न।
2) select_related
यहां सहायता नहीं करता है, क्योंकि Box.content_object
GenericForeignKey
है।
3) django 1.4, prefetch_related
के रूप में GenericForeignKey
एस प्राप्त कर सकते हैं।
print [box for box in Box.objects.prefetch_related('content_object').all()]
यह (बक्से लाने) करता + (सभी बक्से के लिए सेब और चॉकलेट लाने) + एन (लाने प्रत्येक एप्पल और फैक्टरी प्रत्येक चॉकलेट के लिए के लिए फार्म) प्रश्नों।
4) स्पष्ट रूप से prefetch_related
जेनेरिक फॉर्निनेकीज़ के विदेशी क्षेत्रों का पालन करने के लिए पर्याप्त स्मार्ट नहीं है। अगर मैं कोशिश:
print [box for box in Box.objects.prefetch_related( 'content_object__farm', 'content_object__factory').all()]
यह हक शिकायत है कि Chocolate
वस्तुओं एक farm
क्षेत्र नहीं है, और इसके विपरीत।
5) मैं कर सकता:
apple_ctype = ContentType.objects.get_for_model(Apple)
chocolate_ctype = ContentType.objects.get_for_model(Chocolate)
boxes_with_apples = Box.objects.filter(content_type=apple_ctype).prefetch_related('content_object__farm')
boxes_with_chocolates = Box.objects.filter(content_type=chocolate_ctype).prefetch_related('content_object__factory')
यह है (बक्से लाने) + (सभी बक्से के लिए सेब और चॉकलेट) + (सभी सेब के लिए फार्म लाने लाने और सभी चॉकलेट के लिए कारखानों) प्रश्न। नकारात्मकता यह है कि मुझे मैन्युअल रूप से दो क्वेरीसेट्स (boxes_with_apples
, boxes_with_chocolates
) को मर्ज और सॉर्ट करना होगा। मेरे असली एप्लिकेशन में, मैं इन बॉक्सों को एक पेजिनेटेड मॉडलएडमिन में प्रदर्शित कर रहा हूं। यह स्पष्ट नहीं है कि इस समाधान को कैसे एकीकृत किया जाए। शायद मैं इस कैशिंग को पारदर्शी रूप से करने के लिए एक कस्टम पेजिनेटर लिख सकता हूं?
6) मैं this पर आधारित कुछ जोड़ सकता हूं जो ओ (1) प्रश्न भी करता है। लेकिन अगर मैं इससे बच सकता हूं तो मैं आंतरिक (_content_object_cache
) के साथ गड़बड़ नहीं करूंगा।
सारांश में: एक बॉक्स को प्रिंट करने के लिए जेनेरिक फॉर्निनेकी के विदेशी क्षेत्रों तक पहुंच की आवश्यकता होती है। मैं ओ (1) प्रश्नों में एन बॉक्स कैसे मुद्रित कर सकता हूं? है (5) सबसे अच्छा मैं कर सकता हूं, या क्या कोई आसान समाधान है?
बोनस अंक: इस तरह के प्रश्नों को आसान बनाने के लिए आप इस डीबी स्कीमा को कैसे प्रतिक्रिया देंगे?
का उपयोग आप 'कुछ साधारण नाम के नाम बदलते हैं farm' /' factory' काम prefetch_related होगा 'creator', जैसे,? – Igor
दरअसल, 'prefetch_related (' content_object__creator ') आपके सुझाए गए नाम के बाद काम करता है। दुर्भाग्यवश, नाम आपके द्वारा ऐप्पल/फार्म और चॉकलेट/फैक्ट्री के स्थान पर मौजूद वास्तविक मॉडल के आधार पर समझ सकता है या नहीं। – cberzan