过滤具有多对多关系的对象,检查它是否包含列表中的至少一个元素

时间:2019-04-08 17:18:21

标签: python django django-models django-views

我们正在制作一个用于出售二手商品的应用。在此应用程序内部,我们可以选择根据一系列条件过滤产品:用户的地理位置和最大距离,最小价格,最大价格,最小得分和标签列表。

我的主要问题是过滤产品与标签之间的多对多关系。我们要做的是获取所有包含至少一个用户选择的标签之一的产品。

以下是过滤器功能的代码:

def FilterProduct(request, format=None):
    if request.method != 'POST':
        return Response(status=status.HTTP_400_BAD_REQUEST)
    token = request.POST.get('token', 'nothing')
    if token == 'nothing':
        return Response(status=status.HTTP_400_BAD_REQUEST)
    else:
        try:
            tags = request.POST.get('tags', '')
            tags_pk = []
            for tag_search in tags:
                tag = Tag.objects.filter(nombre=tag_search)
                if tag != None:
                    tags_pk.append(tag.pk)

            user_latitude = request.POST.get('latitud', '')
            user_longitude = request.POST.get('longitud', '')
            max_distance = request.POST.get('distancia_maxima', '')
            min_price = request.POST.get('precio_minimo', '')
            max_price = request.POST.get('precio_maximo', '')
            min_score = request.POST.get('calificacion_minima', '')
            if tags == '' or user_latitude == '' or user_longitude == '' or max_distance == '' or min_price == '' or max_price == '' or min_score == '':
                return Response(status=status.HTTP_400_BAD_REQUEST)
            products = Productos.objects.filter(precio__lte=max_price, precio__gte=min_price, vendido_por__media_valoraciones__gte=min_score, tiene_tags__in=tags_pk)

由于某种原因,这不会返回所有至少包含主键列表中一项的产品。

这是models.py:

class Producto(models.Model):
    vendido_por = models.ForeignKey(
        to=Usuario,
        null=False,
        on_delete=models.CASCADE,
        verbose_name='Usuario que ha puesto a la venta el producto',
        related_name='producto_del_usuario')
    latitud = models.DecimalField(
        verbose_name='Latitud del producto',
        max_digits=9,
        decimal_places=6)
    longitud = models.DecimalField(
        verbose_name='Longitud del producto',
        max_digits=9,
        decimal_places=6)
    nombre = models.CharField(
        max_length=50,
        verbose_name='Nombre del producto')
    precio = models.CharField(
        max_length=10,
        verbose_name='Precio del producto')
    estado_producto = models.CharField(
        max_length=50,
        choices=[(tag.name, tag.value) for tag in EleccionEstadoProducto],
        verbose_name='Estado en el que se encuentra el producto: Nuevo, Semi-nuevo, etc')
    estado_venta = models.CharField(
        max_length=50,
        choices=[(tag.name, tag.value) for tag in EleccionEstadoVenta],
        verbose_name='Estado en el que se encuentra la venta')
    num_acciones = models.IntegerField(
        default=0,
        verbose_name='Marca si uno o los dos usuarios han confirmado el estado de venta')
    tipo_envio = models.CharField(
        max_length=50,
        verbose_name='Si el usuario que ha colgado el producto esta dispuestos a enviar a domicilio o no')
    descripcion = models.CharField(
        max_length=1000,
        verbose_name='Descripcion asociada al producto')
    tiene_tags = models.ManyToManyField(
        Tag,
        blank=True,
        editable=True,
        related_name='tiene_tags')
    le_gusta_a = models.ManyToManyField(
        Usuario,
        blank=True,
        editable=True,
        related_name='le_gusta_a')
    num_likes = models.IntegerField(
        default=0,
        verbose_name='Likes acumulados por el producto')

class Tag(models.Model):
    nombre = models.CharField(
        max_length=50,
        verbose_name='Nombre del tag')
    es_predeterminado = models.BooleanField(
        default=False,
        verbose_name='Marca si un tag ha sido creado por los administradores de la aplicacion')

有没有一种实际的方法来过滤所有包含至少一个包含在请求中发送的标签中的标签之一的产品?

谢谢!

1 个答案:

答案 0 :(得分:2)

我认为您可以简化标记过滤器的工作方式,例如

awk -v occur="2" -F' = ' '/token/{if(++count==occur){print;exit}}'  config.txt

然后,您可以将查询集直接放入产品过滤器中,例如

tags = request.POST.get('tags', '')
tag_queryset = Tag.objects.filter(nombre__in=tags)

希望有帮助