2010-11-26 12 views

Respuesta

17

Como indica el error, no puede llamar al update() en un QuerySet si sacó un segmento.

La razón:

  1. Teniendo un segmento es equivalente a una declaración LIMIT en SQL.
  2. La emisión de una actualización convierte su consulta en una declaración UPDATE.

Lo que estamos tratando de hacer sería equivalente a

UPDATE ... WHERE ... LIMIT 5

que no es posible, al menos no con el estándar SQL.

+5

Muchas gracias. Veo mi error ¿Hay alguna solución para esto? (¿aparte de hacer un bucle sobre los pks y actualizar cada uno?) – xpanta

+0

'ACTUALIZACIÓN ... DONDE ... LÍMITE 1' es posible en MySQL. Muy útil para evitar bloqueos "SELECCIONAR ... PARA ACTUALIZAR". – est

+0

@est tienes razón, amplié ligeramente mi respuesta. Tenga en cuenta que OP nunca menciona el tipo de base de datos que se utiliza. –

43

El documentation suggests que algo como lo siguiente podría ser posible - no estoy seguro de si hacer la limitación en un interior QuerySet no pasa por el cheque por ahí llamando update() después de cortar:

inner_q = UserLog.objects.filter(user=user, 
           action='message', 
           timestamp__lt=now).values('pk')[0:5] 
UserLog.objects.filter(pk__in=inner_q).update(read=True) 

De no ser así, se podría utilizar el in field lookup así:

ids = UserLog.objects.filter(user=user, 
          action='message', 
          timestamp__lt=now).values_list('pk', flat=True)[0:5] 
UserLog.objects.filter(pk__in=list(ids)).update(read=True) 
+2

primer método funcionó para mí. no intenté el segundo. –

+0

no es seguro para subprocesos. utilice "SELECCIONAR ... PARA ACTUALIZAR" – est

+1

Uno probablemente debería colocar estos dentro "con el bloque transaction.atomic():". –

1

que estaba recibiendo la misma err o cuando se intenta limitar el número de registros devueltos por un conjunto de consulta.

Encontré que si estamos usando uno de class-based generic views de Django como ArchiveIndexView, podemos usar el atributo paginate_by = para limitar el número de registros.

Por ejemplo (en views.py):

from django.views.generic import ArchiveIndexView 
from .models import Entry 

class HomeListView(ArchiveIndexView): 
    """ Blog Homepage """ 
    model = Entry 
    date_field = 'pub_date' 
    template_name = 'appname/home.html' 
    queryset = Entry.objects.filter(
     is_active=True).order_by('-pub_date', 'title') 
    paginate_by = 30 
+1

Esto es bastante agradable y limpio, siempre que no desee la paginación. Supongo que también podría refunfuñar que está haciendo que el código no sea claro, ya que está diciendo que está paginado, pero luego no lo paginó en la plantilla, pero es mucho más rápido y más fácil de entender que lo que está sucediendo que otros métodos. –

0

Si desea cortar algunos de los resultados de un conjunto de consultas, puede copiarlo a otra variable (una copia superficial es suficiente, que es más rápido que un copia profunda, ya que sólo utiliza referencias a los originales objetos.)

import copy 

queryset = Mytable.objects.all() 
pieceOfQuery = copy.copy(queryset) 
pieceOfQuery = pieceOfQuery[:10] 

Esto mantendrá Django de quejarse si tiene un filtro order_by en su ta ble, ya que eso sucede después del corte si lo haces en el objeto de consulta principal

Cuestiones relacionadas