select_for_update() issues SELECT ...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | # ====================================================================== # `select_for_update()` issues `SELECT ... FOR UPDATE` to lock rows for the # transaction; `skip_locked=True` skips rows another transaction already holds # (a simple work-queue pattern). `QuerySet.explain()` returns PostgreSQL's query # plan — how it will execute. # ====================================================================== # ---------------------------------------------------------------------- # select_for_update(skip_locked=True) — row locking # ---------------------------------------------------------------------- # Django: with transaction.atomic(): rows = list( Book.objects.select_for_update(skip_locked=True).order_by("id")[:3] ) # SQL: # BEGIN # # SELECT "examples_book"."id", "examples_book"."title", "examples_book"."author_id", "examples_book"."price", "examples_book"."pages", "examples_book"."published", "examples_book"."is_active", "examples_book"."tags", "examples_book"."data", "examples_book"."search", "examples_book"."title_upper" # FROM "examples_book" # ORDER BY "examples_book"."id" ASC # LIMIT 3 FOR UPDATE SKIP LOCKED # # COMMIT # Result: # locked & fetched: Harry Potter # locked & fetched: The Hobbit # locked & fetched: The Lord of the Rings # ---------------------------------------------------------------------- # QuerySet.explain() — PostgreSQL's query plan # ---------------------------------------------------------------------- # Django: Book.objects.filter(price__gt=10).explain() # Result: # Seq Scan on examples_book (cost=0.00..1.05 rows=3 width=222) # Filter: (price > '10'::numeric) |