es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

SearchVectorField – no se permite la referencia conjunta para el campo taggit

Mi definición del modelo es la siguiente (un modelo simplificado del que se utiliza en el producto real. Hay un par de otros campos):

from django.db import models
from taggit.managers import TaggableManager

from django.contrib.postgres.search import SearchVectorField
from django.contrib.postgres.indexes import GinIndex

class Product(models.Model):
    tags = TaggableManager()
    search_vector = SearchVectorField(null=True)

    class Meta:
        indexes = [
            GinIndex(fields=['search_vector'])
        ]

Ejecuto los comandos make migrations y migrate. Estos funcionan correctamente.

Luego ejecuto el siguiente conjunto de comandos para construir el índice:

search_vector = SearchVector('tags__name')
Product.objects.all().update(search_vector=search_vector)

Obtengo el siguiente error:

django.core.exceptions.FieldError: Las referencias a campos unidos no están permitidas en esta consulta.

Esto claramente se produce debido al campo tags__name, pero no estoy seguro de cómo solucionarlo.

¿Alguien puede explicar qué debo hacer para ejecutar correctamente los comandos anteriores?

¡Gracias!

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    El error que estás recibiendo se debe a que tags__name es una referencia de campo unido, lo cual no está permitido en consultas de actualización masiva. Para ejecutar correctamente los comandos anteriores, necesitarías utilizar una subconsulta para obtener el resultado deseado.

    Aquí tienes un ejemplo de cómo podrías modificar el código anterior para utilizar una subconsulta en su lugar:

    from django.db.models import F
    
    search_vector = SearchVector('tags__name')
    subquery = Product.tags.through.objects.filter(
        product_id=OuterRef('pk')
    ).values('tag_id')
    Product.objects.annotate(
        tag_ids=Subquery(subquery)
    ).annotate(
        search_vector=search_vector
    ).update(search_vector=F('search_vector') | search_vector)
    

    En este código modificado, utilizamos una subconsulta para obtener los valores de tag_id para cada objeto Product, y luego utilizamos esos valores para anotar la queryset con un campo tag_ids. Luego utilizamos ese campo tag_ids para generar el search_vector para cada objeto Product, y finalmente actualizamos el campo search_vector de todos los objetos Product en una única consulta de actualización masiva.

    ¡Espero que esto te ayude! Avísame si tienes alguna otra pregunta.

Comments are closed.