queryset objects listas lista interseccion gte entre diferencia conjuntos conjunto __gte python django django-models django-views tagging

python - objects - Unión e intersección en Django



union e interseccion de conjuntos en c++ (4)

Esto hará el truco para ti

Blog.objects.filter(tags__name__in=[''tag1'', ''tag2'']).annotate(tag_matches=models.Count(tags)).filter(tag_matches=2)

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

Modelos simples solo para hacer mi pregunta.

Me pregunto cómo puedo consultar blogs usando etiquetas de dos maneras diferentes.

  • Entradas de blog etiquetadas con "tag1" o "tag2": Blog.objects.filter(tags_in=[1,2]).distinct()
  • Los objetos del blog que están etiquetados con "tag1" y "tag2" :?
  • Los objetos del blog etiquetados con exactamente "tag1" y "tag2" y nada más: ??

La etiqueta y el blog solo se usan como ejemplo.


He probado esto con Django 1.0:

Las consultas "o":

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

o podrías usar la clase Q:

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

La consulta "y":

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

No estoy seguro acerca de la tercera, probablemente deba bajar a SQL para hacerlo.


Podría usar objetos Q para # 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'') )

Creo que las uniones e intersecciones están un poco fuera del alcance del ORM de Django, pero es posible que esto ocurra. Los siguientes ejemplos provienen de una aplicación de Django llamada django-tagging que proporciona la funcionalidad. Línea 346 de models.py :

Para la segunda parte, estás buscando una unión de dos consultas, básicamente

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

Para la parte # 3, creo que estás buscando una intersección. Vea la línea 307 de 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()


Por favor, no reinvente la rueda y use la django-tagging que fue hecha exactamente para su caso de uso. Puede hacer todas las consultas que describes, y mucho más.

Si necesita agregar campos personalizados a su modelo de Etiqueta, también puede echar un vistazo a mi rama de django-etiquetado .