سؤال

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

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

نماذج بسيطة فقط أن أسأل سؤالي.

وأتساءل كيف يمكنني الاستعلام بلوق باستخدام الكلمات بطريقتين مختلفتين.

  • بلوق إدخالات الموسومة ب "tag1" أو "tag2":Blog.objects.filter(tags_in=[1,2]).distinct()
  • بلوق الأشياء التي هي ذات الكلمات الدلالية مع "tag1" و "tag2" : ?
  • بلوق الأشياء التي هي ذات الكلمات الدلالية مع بالضبط "tag1" و "tag2" ولا شيء آخر : ??

العلامة بلوق هو مجرد مثال على ذلك.

هل كانت مفيدة؟

المحلول

هل يمكن استخدام Q الكائنات #1:

# 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')
)

النقابات و التقاطعات أعتقد قليلا خارج نطاق جانغو ORM ، ولكن من الممكن أن هذه.الأمثلة التالية هي من جانغو تطبيق يسمى جانغو-tagging الذي يوفر وظائف. خط 346 من models.py:

في الجزء الثاني ، كنت تبحث عن اتحاد اثنين من الاستعلامات في الأساس

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()

الجزء #3 أعتقد أنك تبحث عن التقاطع.انظر خط 307 من 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()

نصائح أخرى

لقد اختبرت هذه مع جانغو 1.0:

فإن "أو" الاستفسارات:

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

أو يمكنك استخدام Q الدرجة:

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

"و" الاستعلام:

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

لست متأكدا عن الثالثة, سوف تحتاج على الأرجح الهبوط إلى SQL للقيام بذلك.

من فضلك لا إعادة اختراع العجلة و استخدام جانغو-tagging التطبيق والتي كانت مصنوعة تماما للاستخدام الخاص بك الحالة.يمكن أن تفعل كل الاستفسارات تصفون, وأكثر من ذلك بكثير.

إذا كنت بحاجة إلى إضافة حقول مخصصة العلامة النموذج, يمكنك أيضا أن تأخذ نظرة على فرع بلدي جانغو-tagging.

هذا سوف تفعل خدعة لك

Blog.objects.filter(tags__name__in=['tag1', 'tag2']).annotate(tag_matches=models.Count(tags)).filter(tag_matches=2)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top