문제

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" 태그가 지정되고 다른 태그는 지정되지 않은 블로그 개체: ??

태그와 블로그는 예시로만 사용되었습니다.

도움이 되었습니까?

해결책

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

내 생각에 Union과 Intersection은 Django ORM의 범위를 약간 벗어나지만 가능합니다.다음 예제는 Django 애플리케이션에서 가져온 것입니다. 장고 태깅 기능을 제공하는 것입니다. models.py의 346번째 줄:

2부에서는 기본적으로 두 쿼리의 통합을 찾고 있습니다.

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에서는 당신이 교차점을 찾고 있다고 생각합니다.보다 models.py의 307번째 줄

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

다른 팁

나는 이것을 Django 1.0으로 테스트했습니다:

"또는" 쿼리:

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

또는 Q 클래스를 사용할 수도 있습니다.

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

"and" 쿼리:

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

세 번째에 대해서는 잘 모르겠습니다. 이를 수행하려면 SQL을 사용해야 할 것입니다.

바퀴를 재발명하지 말고 사용하세요. django 태깅 애플리케이션 이는 귀하의 사용 사례에 맞게 정확하게 만들어졌습니다.설명하는 모든 쿼리 등을 수행할 수 있습니다.

태그 모델에 사용자 정의 필드를 추가해야 하는 경우 다음을 살펴볼 수도 있습니다. 내 장고 태그 지정 지점.

이것은 당신을 위해 트릭을 할 것입니다

Blog.objects.filter(tags__name__in=['tag1', 'tag2']).annotate(tag_matches=models.Count(tags)).filter(tag_matches=2)
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top