2010-11-26 10 views
14

私はこれを行うにしようとしていますが取られた後、クエリを更新できませんDjangoは:スライスが

Cannot update a query once a slice has been taken. 

(ジャンゴ1.2.1を使用して)

私は間違っていますか?

答えて

17

スライスを取り出した場合は、エラーが発生したため、クエリセットでupdate()を呼び出すことはできません。

理由:

  1. スライスを取るには、SQLでLIMIT文と同じです。
  2. 更新を発行すると、クエリはUPDATEステートメントに変わります。
  3. 何をしようとする

は、標準SQLで、少なくとも、可能ではないではありません

UPDATE ... WHERE ... LIMIT 5

に相当します。

+5

ありがとう、ありがとう。私は私の誤りを見る。このための回避策はありますか? (pksをループし、それぞれを更新する以外は?) – xpanta

+0

MySQLでは 'UPDATE ... WHERE ... LIMIT 1 'が可能です。 "SELECT ... FOR UPDATE"ロックを避けるためには非常に便利です。 – est

+0

あなたは正しいです、私は少し答えを広げました。 OPは使用されるデータベースのタイプを決して言及しないことに注意してください。 –

43

のようなものが可能かもしれないdocumentation suggests - 私は、スライスした後、内QuerySetに制限を行うことupdate()を呼び出す周りのチェックを迂回するかはわからない:

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) 

あなたがそうのようなin field lookupを使用することができ、それに失敗:

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

最初の方法は私のために働いた。もう1つは試しませんでした。 –

+0

スレッドセーフではありません。 "SELECT ... FOR UPDATE"を使用してください – est

+1

おそらく、これらは "transaction.atomic():"ブロック内に配置してください。 –

1

私は同じERRを得ていましたまたはクエリーセットによって返されたレコードの数を制限しようとするときに発生します。

ArchiveIndexViewのようなDjangoのclass-based generic viewsのいずれかを使用している場合は、paginate_by =属性を使用してレコード数を制限できます。

例えば

(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

ページネーションが必要でない限り、これはかなりきれいで清潔です。私はあなたがコードを不明瞭にしていると不平を言うかもしれないと思うのですが、それはページングされていると言われていますが、テンプレート内ではページ切られていないと言えるからです。 –

0

あなたはクエリセットの結果の一部をスライスしたい場合は、コピーすることができ、それは別の変数にそれを (浅いコピーで十分です、それだけで元 オブジェクトへの参照を使用しているため、深いコピーより 高速です。)

import copy 

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

このお あなたのTAにORDER_BYフィルターを持っている場合は文句からジャンゴを維持しますあなたがメインでそれを行うとスライシング後に起こるので、 クエリーセットオブジェクト

関連する問題