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.

[Django][DRF] ¿Cómo obtener un conjunto de consultas DESORDENADO a partir de `.filter`?

Antes que nada, no soy un hablante nativo de inglés, así que por favor ten paciencia con mis habilidades en inglés o dame algunos consejos.

(Para tu información, Django versión 3.2.9 y DRF versión 3.12.4 con PostgreSQL versión 12.7)

Estoy escribiendo una API para crear una publicación utilizando el serializador de DRF. Y me he enfrentado a un problema con “el orden en el que se agregan las etiquetas a la publicación”.

  • Los modelos de publicación y etiquetas están conectados a través de un campo M2M.

Lo que significa que, digamos que añado las etiquetas a, b y c en una publicación. La lógica que estoy utilizando es la siguiente.

# Clase Serializador
# def create(instancia):
# instancia: instancia específica de la publicación

tags = ['t', 'a', 'g', 's']
Tag.objects.bulk_create([Tag(name=tag) for tag in tags])
instancia.tags.add(*[tag for tag in Tag.objects.filter(name__in=tags)])

Ejecuta esto al principio. Las etiquetas se agregan en este orden.

TagQuerySet[Tag<'t'>, Tag<'a'>, Tag<'g'>, Tag<'s'>]

Y mi API recibe otra solicitud de creación que incluye las etiquetas existentes, por ejemplo,

tags = ['g', 'a', 's']

Django las agrega en orden ascendente, no en el orden que quiero, como por ejemplo,

# Etiquetas de la nueva instancia creada
TagQuerySet[Tag<'a'>, Tag<'g'>, Tag<'s'>]

Sé que puedo agregar las etiquetas siguiendo mi orden de lista usando un bucle for,

for tag in tags:
    instancia.tags.add(Tag.objects.get(name=tag))

pero no es eficiente.

Entonces mi pregunta es:

  • ¿Cómo puedo obtener una consulta utilizando .filter siguiendo el orden de mi lista?
  • Si no hay forma de hacer esto, ¿cuál es la forma eficiente de agregar etiquetas a la publicación?
Tags:  , , , ,

Answer

  1. Avatar for davy.ai
    1. Cómo obtener un queryset utilizando .filter siguiendo el orden de mi lista

    Desafortunadamente, .filter() no admite la ordenación en el orden de la lista de entrada. Según la documentación de Django, el orden de los resultados al utilizar .filter() es indefinido (https://docs.djangoproject.com/en/3.2/topics/db/queries/#retrieving-specific-objects-with-filters). Por lo tanto, no puedes confiar en el orden en el que los elementos de la lista son devueltos por el método .filter().

    1. Forma eficiente de agregar etiquetas a una publicación

    Una forma eficiente de agregar etiquetas a una publicación es verificar primero si la etiqueta ya existe en la base de datos. Si la etiqueta ya existe, simplemente puedes usar .add() para agregar la etiqueta a la publicación. Si la etiqueta no existe, puedes crear una nueva etiqueta utilizando .create() y luego usar .add() para agregarla a la publicación. Aquí tienes un ejemplo de código:

    def create_post(request):
        # Obtén los datos de la publicación de la solicitud
        # ...
    
        # Obtén las etiquetas de los datos de la publicación
        tags = post_data.get('tags', [])
    
        # Agrega las etiquetas a la publicación
        tag_objs = []
        for tag_name in tags:
            try:
                # Intenta obtener la etiqueta de la base de datos
                tag_objs.append(Tag.objects.get(name=tag_name))
            except Tag.DoesNotExist:
                # Si la etiqueta no existe, crea una nueva
                tag_objs.append(Tag.objects.create(name=tag_name))
    
        post = Post.objects.create(title=title, content=content)
        post.tags.add(*tag_objs)
    
        return Response({'message': 'Publicación creada exitosamente'})
    

    Este código primero obtiene las etiquetas de los datos de la publicación y luego las recorre en un bucle para verificar si existen en la base de datos. Si una etiqueta ya existe, la agrega a una lista de objetos de etiqueta (tag_objs). Si una etiqueta no existe, crea una nueva etiqueta y la agrega a la lista.

    Finalmente, el código crea una nueva publicación y agrega la lista de objetos de etiqueta a ella utilizando .add(). De esta manera, se conserva el orden de las etiquetas en la lista de entrada y las etiquetas se agregan eficientemente a la publicación.

Comments are closed.