ठीक है, वे कुछ अस्पष्ट तालिका और फ़ील्ड नाम हैं, लेकिन सबसे अच्छा मैं यह बता सकता हूं कि क्वेरी कुछ इस तरह दिखेगी:
(Restaurant.objects.filter(city=8,
cuisine__cuisinetype__cuisine="Italian").distinct().order_by('name')[:20])
लेकिन जब तक आप उस डेटाबेस स्कीमा में बंद नहीं होंगे, तब तक आपके मॉडल बेहतर दिखाई देंगे:
class CuisineType(models.Model):
name = models.CharField(max_length=50)
class Meta:
db_table = 'cuisinetype'
class Restaurants(models.Model):
city = models.ForeignKey("City", null=True, blank=True) # Apparently defined elsewhere. Should be part of location?
name = models.CharField(max_length=50)
location = models.ForeignKey("Location", null=True, blank=True) # Apparently defined elsewhere.
cuisines = models.ManyToManyField(CuisineType)
तब क्वेरी अधिक पसंद की जाएगी:
Restaurant.objects.filter(city=8, cuisines__name="Italian").order_by('name')[:20]
ठीक है, यह मानकर कि आपके कोड में कोई परिवर्तन नहीं हुआ है, चलिए आपकी क्वेरी पर चलते हैं। हम सबक्वेरी से शुरू करेंगे।
SELECT DISTINCT res_id FROM cuisine
JOIN cuisinetype ON cuisine.cuisineid = cuisinetype.`cuisineid`
WHERE cuisinetype.`cuisine` = 'Italian'
हम WHERE क्लॉज को देखते हैं और देखते हैं कि हमें JOIN की जरूरत है। जॉइन करने के लिए, आपको जॉइन किए गए मॉडलों में से एक में एक रिलेशनल फील्ड घोषित करना होगा (Django एक रिवर्स रिलेशन जोड़ देगा, जिसे हमें नाम देना चाहिए)। इसलिए हम मिलान कर रहे हैं cuisine.cuisineid
`cuisinetype.cuisineid के साथ। यह कुछ भयानक नामकरण है।
यह कई-से-अनेक संबंध है, इसलिए हमें एक ManyToManyField
की आवश्यकता है . खैर, Cuisine
को देख रहे हैं मॉडल, यह वास्तव में इस M2M के लिए जॉइनिंग टेबल है। Django को उम्मीद है कि एक जॉइनिंग टेबल में दो ForeignKey
होंगे क्षेत्र, एक जोड़ के प्रत्येक पक्ष की ओर इशारा करते हुए। आम तौर पर यह आपके लिए विवेक को बचाने के लिए इसे बनाएगा। जाहिर तौर पर आप इतने भाग्यशाली नहीं हैं। तो आपको इसे मैन्युअल रूप से जोड़ना होगा।
ऐसा लगता है कि "जीआईडी" फ़ील्ड रिकॉर्ड के लिए एक (बेकार) आईडी फ़ील्ड है, तो आइए मान लें कि यह ऑटो-इंक्रीमेंट पूर्णांक है। (सुनिश्चित करने के लिए, CREATE TABLE कमांड देखें।) अब हम Cuisine
को फिर से लिख सकते हैं। कुछ समझदार में मॉडल:
class Cuisine(models.Model):
cuisinegid = models.AutoField(primary_key=True, db_column='CuisineGID')
cuisineid = models.ForeignKey("Cuisinetype", null=True,
db_column='CuisineID', blank=True)
res_id = models.ForeignKey("Restaurant", null=True, db_column='Res_ID',
blank=True)
class Meta:
db_table = 'cuisine'
मॉडल के नाम उद्धृत किए गए हैं क्योंकि मॉडल को अभी तक परिभाषित नहीं किया गया है (वे बाद में फ़ाइल में हैं)। अब कोई आवश्यकता नहीं है कि Django फ़ील्ड नाम कॉलम नामों से मेल खाते हों, तो चलिए उन्हें कुछ और पढ़ने योग्य में बदलते हैं। रिकॉर्ड आईडी फ़ील्ड को आमतौर पर id
. नाम दिया जाता है , और विदेशी कुंजियों का नाम आमतौर पर उनके नाम पर रखा जाता है:
class Cuisine(models.Model):
id = models.AutoField(primary_key=True, db_column='CuisineGID')
cuisine_type = models.ForeignKey("CuisineType", null=True,
db_column='CuisineID', blank=True)
restaurant = models.ForeignKey("Restaurant", null=True, db_column='Res_ID',
blank=True)
class Meta:
db_table = 'cuisine'
ठीक है, हमने अपनी संयुक्त तालिका को परिभाषित कर लिया है। जब तक हम इस पर हैं, उसी सामान को हमारे Cuisinetype
. पर लागू करते हैं आदर्श। सही ऊंट-केस वर्ग के नाम पर ध्यान दें:
class CuisineType(models.Model):
id = models.AutoField(primary_key=True, db_column='CuisineID')
name = models.CharField(max_length=50, db_column='Cuisine', blank=True)
class Meta:
db_table = 'cuisinetype'
तो हम अंत में अपने Restaurant
. पर पहुंच जाते हैं आदर्श। ध्यान दें कि नाम एकवचन; . है ऑब्जेक्ट केवल एक रिकॉर्ड का प्रतिनिधित्व करता है।
मैंने देखा है कि इसमें किसी dp_table
का अभाव है या db_column
सामान, इसलिए मैं एक अंग पर जा रहा हूं और अनुमान लगा रहा हूं कि Django इसे बना रहा है। इसका मतलब है कि हम इसे id
बनाने दे सकते हैं हमारे लिए फ़ील्ड और हम इसे अपने कोड से हटा सकते हैं। (यदि ऐसा नहीं है, तो हम इसे अन्य मॉडलों की तरह ही जोड़ देते हैं। लेकिन आपके पास वास्तव में एक अशक्त रिकॉर्ड आईडी नहीं होनी चाहिए।) और यह वह जगह है जहां हमारा व्यंजन ManyToManyField
टाइप करता है। जीवन:
class Restaurants(models.Model):
city_id = models.ForeignKey(null=True, blank=True)
name = models.CharField(max_length=50, blank=True)
location = models.ForeignKey(null=True, blank=True)
cuisine_types = models.ManyToManyField(CuisineType, through=Cuisine,
null=True, blank=True)
ध्यान दें कि M2M फ़ील्ड का नाम बहुवचन है, क्योंकि उस संबंध से कई रिकॉर्ड बनते हैं।
इस मॉडल में एक और चीज जो हम जोड़ना चाहेंगे वह है उल्टे संबंधों के नाम। दूसरे शब्दों में, अन्य मॉडलों से वापस Restaurant
में कैसे जाएं . हम related_name
. जोड़कर ऐसा करते हैं पैरामीटर। उनके लिए समान होना असामान्य नहीं है।
class Restaurant(models.Model):
city_id = models.ForeignKey(null=True, blank=True,
related_name="restaurants")
name = models.CharField(max_length=50, blank=True)
location = models.ForeignKey(null=True, blank=True,
related_name="restaurants")
cuisine_types = models.ManyToManyField(CuisineType, through=Cuisine,
null=True, blank=True, related_name="restaurants")
अब हम अंत में सेट हो गए हैं। तो आइए आपकी क्वेरी देखें:
SELECT restaurants.`name`, restaurants.`address`, cuisinetype.`cuisine`
FROM restaurants
JOIN cuisinetype ON cuisinetype.cuisineid = restaurants.`cuisine`
WHERE city_id = 8 AND restaurants.id IN (
SELECT DISTINCT res_id FROM cuisine
JOIN cuisinetype ON cuisine.cuisineid = cuisinetype.`cuisineid`
WHERE cuisinetype.`cuisine` = 'Italian')
ORDER BY restaurants.`name`
LIMIT 20
चूंकि यह FROM restaurants
है , हम उस मॉडल के डिफ़ॉल्ट ऑब्जेक्ट मैनेजर, objects
. से शुरू करेंगे :
Restaurant.objects
WHERE
इस मामले में क्लॉज एक filter()
है कॉल करें, इसलिए हम इसे पहले टर्म के लिए जोड़ते हैं:
Restaurant.objects.filter(city=8)
आपके पास प्राथमिक कुंजी मान या City
हो सकता है उस शब्द के दाहिने हाथ की ओर वस्तु। हालाँकि, शेष क्वेरी अधिक जटिल हो जाती है, क्योंकि इसके लिए JOIN
. की आवश्यकता होती है . Django में एक जुड़ाव सिर्फ संबंध क्षेत्र के माध्यम से dereferencing जैसा दिखता है। किसी क्वेरी में, इसका मतलब है कि प्रासंगिक फ़ील्ड नामों को डबल अंडरस्कोर के साथ जोड़ना:
Restaurant.objects.filter(city=8, cuisine_type__name="Italian")
Django जानता है कि किन क्षेत्रों में शामिल होना है क्योंकि यह Cuisine
. में घोषित किया गया है तालिका जो through=Cuisine
. द्वारा खींची जाती है cuisine_types
. में पैरामीटर . यह एक सबक्वेरी करना भी जानता है क्योंकि आप एक M2M संबंध से गुजर रहे हैं।
तो यह हमें SQL के बराबर प्राप्त करता है:
SELECT restaurants.`name`, restaurants.`address`
FROM restaurants
WHERE city_id = 8 AND restaurants.id IN (
SELECT res_id FROM cuisine
JOIN cuisinetype ON cuisine.cuisineid = cuisinetype.`cuisineid`
WHERE cuisinetype.`cuisine` = 'Italian')
आधे रास्ते वहाँ। अब हमें चाहिए SELECT DISTINCT
इसलिए हमें एक ही रिकॉर्ड की एक से अधिक प्रतियां नहीं मिलती हैं:
Restaurant.objects.filter(city=8, cuisine_type__name="Italian").distinct()
और आपको प्रदर्शन के लिए व्यंजनों के प्रकारों को खींचने की जरूरत है। पता चलता है कि आपके पास जो क्वेरी है वह वहां अक्षम है, क्योंकि यह आपको केवल जॉइन टेबल पर ले जाती है और संबंधित CuisineType
प्राप्त करने के लिए आपको और क्वेरी चलाने की आवश्यकता होती है रिकॉर्ड। क्या लगता है:Django ने आपको कवर किया है।
(Restaurant.objects.filter(city=8, cuisine_type__name="Italian").distinct()
.prefetch_related("cuisine_types"))
Django दो क्वेरी चलाएगा:एक आपकी तरह संयुक्त आईडी प्राप्त करने के लिए, और एक और संबंधित CuisineType
प्राप्त करने के लिए रिकॉर्ड। फिर क्वेरी परिणाम के माध्यम से एक्सेस करने के लिए डेटाबेस में वापस जाने की आवश्यकता नहीं होती है।
अंतिम दो चीज़ें क्रम में हैं:
(Restaurant.objects.filter(city=8, cuisine_type__name="Italian").distinct()
.prefetch_related("cuisine_types").order_by("name"))
और LIMIT
:
(Restaurant.objects.filter(city=8, cuisine_type__name="Italian").distinct()
.prefetch_related("cuisine_types").order_by("name")[:20])
और आपकी क्वेरी (और संबंधित क्वेरी) पायथन की दो पंक्तियों में पैक की गई है। ध्यान रहे, इस समय, क्वेरी को निष्पादित भी नहीं किया गया है। कुछ भी करने से पहले आपको इसे किसी टेम्पलेट की तरह किसी चीज़ में रखना होगा:
def cuisinesearch(request, cuisine):
return render_to_response('cuisinesearch.html', {
'restaurants': (Restaurant.objects.filter(city=8,
cuisine_type__name="Italian").distinct()
.prefetch_related("cuisine_types").order_by("name")[:20])
})
साँचा:
{% for restaurant in cuisinesearch %}
<h2>{{ restaurant.name }}</h2>
<div class="location">{{ restaurant.location }}</div>
<h3>Cuisines:</h3>
<ul class="cuisines">{% for ct in restaurant.cuisine_types.all %}
<li>{{ ct.name }}</li>{% endfor %}
</ul>
{% endfor %}