联盟和相交在Django [英] Union and Intersect in Django

查看:108
本文介绍了联盟和相交在Django的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

$ $ $ $ $ $ $ $ $ $ $ $ $

class Blog(models.Model):
name = models.CharField(maxlength =
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:

 #具有曲棍球或django标签的博客。 
from django.db.models import Q
Blog.objects.filter(
Q(tags__name__iexact ='hockey')| Q(tags__name__iexact ='django')

我认为,联盟和交叉点有点超出了Django ORM的范围,但它可能这些。以下示例来自提供功能的称为 django-tagging 的Django应用程序。 models.py :



对于第二部分,您正在寻找两个查询的联合,基本上

 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 

标签= get_tag_list(标签)
tag_count = len(tags)
queryset,model = get_queryset_and_model(queryset_or_model)

如果不是tag_count:
返回model._default_manager.none()

model_table = qn(model._meta.db_table)
#此查询选择所有的具有任何
#给定标签的对象。
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))
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 tags in tags])
object_ids = [row [0] for cursor in cursor.fetchall()]
if len(object_ids)> 0:
return queryset.filter(pk__in = object_ids)
else:
返回model._default_manager.none()

对于第3部分,我相信你正在寻找一个十字路口。请参阅 models.py

  def get_intersection_by_model(self,queryset_or_model,tags):

创建一个` `QuerySet``包含与给定列表的* all *相关联的指定
模型的实例

tags = get_tag_list(tags)
tag_count = len (标签)
queryset,model = get_queryset_and_model(queryset_or_model)

如果不是tag_count:
返回model._default_manager.none()

model_table = qn (model._meta.db_table)
#此查询选择所有
#给定标签的所有对象的ID。
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))
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模型).pk,
'tag_id_placeholders':','。join(['%s'] * tag_count),
'tag_count':tag_count,
}

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


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

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

Simple models just to ask my question.

I wonder how can i query blogs using tags in two different ways.

  • Blog entries that are tagged with "tag1" or "tag2": Blog.objects.filter(tags_in=[1,2]).distinct()
  • Blog objects that are tagged with "tag1" and "tag2" : ?
  • Blog objects that are tagged with exactly "tag1" and "tag2" and nothing else : ??

Tag and Blog is just used for an example.

解决方案

You could use Q objects for #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')
)

Unions and intersections, I believe, are a bit outside the scope of the Django ORM, but its possible to to these. The following examples are from a Django application called called django-tagging that provides the functionality. Line 346 of models.py:

For part two, you're looking for a union of two queries, basically

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

For part #3 I believe you're looking for an intersection. See 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()

这篇关于联盟和相交在Django的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆