2008-09-20 13 views
31
class Tag(models.Model): 
    name = models.CharField(maxlength=100) 

class Blog(models.Model): 
    name = models.CharField(maxlength=100) 
    tags = models.ManyToManyField(Tag) 

सरल मॉडल सिर्फ मेरे प्रश्न पूछने के लिए।Django में संघ और छेड़छाड़

मुझे आश्चर्य है कि मैं टैग्स का उपयोग दो अलग-अलग तरीकों से कैसे कर सकता हूं।

  • ब्लॉग प्रविष्टियों को "tag1" या "tag2" के साथ टैग कर रहे हैं: Blog.objects.filter(tags_in=[1,2]).distinct()
  • ब्लॉग वस्तुओं है कि "tag1" और "tag2" के साथ टैग कर रहे हैं: ?
  • ब्लॉग ऑब्जेक्ट्स जिन्हें बिल्कुल "टैग 1" और "टैग 2" के साथ टैग किया गया है और कुछ भी नहीं: ??

टैग और ब्लॉग सिर्फ एक उदाहरण के लिए प्रयोग किया जाता है।

+0

एक वास्तव में महान जवाब के साथ चेक बाहर [इस सवाल] (http://stackoverflow.com/q/12752601/1226722) चाल करेंगे। उपयोगी हो सकता है (मुझे पता है कि यह प्रश्न ~ 6 साल पुराना है, लेकिन मुझे अभी भी जवाब खोजने के दौरान यह मिला है!) – gregoltsov

+0

यह एक वास्तविक एसक्यूएल यूनियन की बजाय या जहां खंड में एक मुद्दा है। यदि आप एक यूनियन की तलाश में हैं तो https: // stackoverflow पर देखें।कॉम/प्रश्न/4411049/कैसे-कर-मैं-मिल-द-यूनियन-ऑफ-दो-डीजेंगो-क्वेरीसेट – jocassid

उत्तर

21

आप # 1 के लिए Q वस्तुओं इस्तेमाल कर सकते हैं:

# Blogs who have either hockey or django tags. 
from django.db.models import Q 
Blog.objects.filter(
    Q(tags__name__iexact='hockey') | Q(tags__name__iexact='django') 
) 

यूनियनों और चौराहों, मुझे विश्वास है, Django ORM के दायरे से बाहर एक सा है, लेकिन इन करने के लिए यह संभव है। निम्नलिखित उदाहरण Django एप्लिकेशन से हैं जिन्हें django-tagging कहा जाता है जो कार्यक्षमता प्रदान करता है। Line 346 of models.py:

दो भाग के लिए, आप दो प्रश्नों का एक संघ के लिए, # 3 भाग के लिए देख रहे हैं मूल रूप से

def get_union_by_model(self, queryset_or_model, tags): 
    """ 
    Create a ``QuerySet`` containing instances of the specified 
    model associated with *any* of the given list of tags. 
    """ 
    tags = get_tag_list(tags) 
    tag_count = len(tags) 
    queryset, model = get_queryset_and_model(queryset_or_model) 

    if not tag_count: 
     return model._default_manager.none() 

    model_table = qn(model._meta.db_table) 
    # This query selects the ids of all objects which have any of 
    # the given tags. 
    query = """ 
    SELECT %(model_pk)s 
    FROM %(model)s, %(tagged_item)s 
    WHERE %(tagged_item)s.content_type_id = %(content_type_id)s 
     AND %(tagged_item)s.tag_id IN (%(tag_id_placeholders)s) 
     AND %(model_pk)s = %(tagged_item)s.object_id 
    GROUP BY %(model_pk)s""" % { 
     'model_pk': '%s.%s' % (model_table, qn(model._meta.pk.column)), 
     'model': model_table, 
     'tagged_item': qn(self.model._meta.db_table), 
     'content_type_id': ContentType.objects.get_for_model(model).pk, 
     'tag_id_placeholders': ','.join(['%s'] * tag_count), 
    } 

    cursor = connection.cursor() 
    cursor.execute(query, [tag.pk for tag in tags]) 
    object_ids = [row[0] for row in cursor.fetchall()] 
    if len(object_ids) > 0: 
     return queryset.filter(pk__in=object_ids) 
    else: 
     return model._default_manager.none() 

मैं तुम्हें एक चौराहे के लिए देख रहे विश्वास करते हैं। line 307 of models.py

def get_intersection_by_model(self, queryset_or_model, tags): 
    """ 
    Create a ``QuerySet`` containing instances of the specified 
    model associated with *all* of the given list of tags. 
    """ 
    tags = get_tag_list(tags) 
    tag_count = len(tags) 
    queryset, model = get_queryset_and_model(queryset_or_model) 

    if not tag_count: 
     return model._default_manager.none() 

    model_table = qn(model._meta.db_table) 
    # This query selects the ids of all objects which have all the 
    # given tags. 
    query = """ 
    SELECT %(model_pk)s 
    FROM %(model)s, %(tagged_item)s 
    WHERE %(tagged_item)s.content_type_id = %(content_type_id)s 
     AND %(tagged_item)s.tag_id IN (%(tag_id_placeholders)s) 
     AND %(model_pk)s = %(tagged_item)s.object_id 
    GROUP BY %(model_pk)s 
    HAVING COUNT(%(model_pk)s) = %(tag_count)s""" % { 
     'model_pk': '%s.%s' % (model_table, qn(model._meta.pk.column)), 
     'model': model_table, 
     'tagged_item': qn(self.model._meta.db_table), 
     'content_type_id': ContentType.objects.get_for_model(model).pk, 
     'tag_id_placeholders': ','.join(['%s'] * tag_count), 
     'tag_count': tag_count, 
    } 

    cursor = connection.cursor() 
    cursor.execute(query, [tag.pk for tag in tags]) 
    object_ids = [row[0] for row in cursor.fetchall()] 
    if len(object_ids) > 0: 
     return queryset.filter(pk__in=object_ids) 
    else: 
     return model._default_manager.none() 
16

मैं Django 1.0 के साथ इन बाहर परीक्षण किया है देखें:

"या" प्रश्न:

Blog.objects.filter(tags__name__in=['tag1', 'tag2']).distinct() 

या आप क्यू वर्ग इस्तेमाल कर सकते हैं:

Blog.objects.filter(Q(tags__name='tag1') | Q(tags__name='tag2')).distinct() 

"और" क्वेरी:

Blog.objects.filter(tags__name='tag1').filter(tags__name='tag2') 

मुझे तीसरे के बारे में निश्चित नहीं है, आपको शायद इसे करने के लिए एसक्यूएल में जाने की आवश्यकता होगी।

+0

एचआरएम, यह "और" क्वेरी एक आसान चाल की तरह दिखती है, सिवाय इसके कि आप शुरुआत में नहीं जानते होंगे कि कितने बार। फ़िल्टर को लागू करने की आवश्यकता होगी। उपयोगकर्ता कुत्ते + बकरी + बिल्ली की तलाश में हो सकता है, जिस स्थिति में आपको आवश्यकता होगी। दो बार फ़िल्टर करें। – mlissner

+0

"और" क्वेरी के गतिशील अनुप्रयोग के संबंध में - बस टैग के माध्यम से पुनरावृत्ति करें और फ़िल्टरिंग जमा करें: query = query.filter (tag__name = 'tagN') – Lukasz

+0

मुझे लगता है कि पहला उदाहरण चाल है। मैं सोच रहा था कि अलग की जरूरत है या नहीं। एसक्यूएल शब्दों में आप 2 ब्लॉग को ब्लॉगटैगलिंक में ब्लॉग में शामिल करेंगे और ब्लॉगटाग लिंक को एक टैग किए गए ब्लॉग रिकॉर्ड को टैग सेट में कई बार सूचीबद्ध किया जाएगा। – jocassid

9

कृपया पहिया को पुन: पेश न करें और django-tagging application का उपयोग करें जो आपके उपयोग के मामले में बिल्कुल बनाया गया था। यह आपके द्वारा वर्णित सभी प्रश्नों को और अधिक कुछ कर सकता है।

यदि आपको अपने टैग मॉडल में कस्टम फ़ील्ड जोड़ने की आवश्यकता है, तो आप my branch of django-tagging पर भी एक नज़र डाल सकते हैं।

5

इस के लिए आप

Blog.objects.filter(tags__name__in=['tag1', 'tag2']).annotate(tag_matches=models.Count(tags)).filter(tag_matches=2) 
संबंधित मुद्दे