0

I have a QuerySet which contains Page objects, which have page_number attribute. The QuerySet is sorted by page_number, so running [i.page_number for i in pages_query_set] would return something like, for example, [1,2,3,5,6,10,11,13,16,19,21]. My task is to write a method that moves the Page objects so they would be consecutive: in this example, the page that was 5 would become 4, 6 would become 5, 10 would be 6, 11 is 7, 13 is 8, etc.

This is my initial solution, a method inside PageQuerySet class:

def validatePageNumbers(self):
    prev_page = 0
    for page in self:
        if page.page_number > prev_page+1:
            page.page_number = prev_page+1
            page.save()
        prev_page = page.page_number

Functionally, it works fine. But calling save() every time really slows it down (probably due to calling database queries every time). I need to find a faster approach. If there had been only one "gap" in this sequence, I would just slice the QuerySet and use something like sliced_qs.update(page_number=models.F('page_number')-gap), because I've seen a singular update() being much faster than several save(). But the gaps are multiple and pretty random.

So I'm confused. F objects don't seem to support such looping. It would be great if I could use a callable in update(), but I haven't found any information about that in docs, nor it works when I try it. Is there a way to apply update() here? Or maybe some other way to make this method faster?

Highstaker
  • 1,015
  • 2
  • 12
  • 28

1 Answers1

0

The solution to this and numerous other bottlenecks was quite simple.

from django.db import transaction

with transaction.atomic():
    #do stuff here

Guess it wraps it all into a single transaction and hits the database only once. This answer has helped a lot here.

Community
  • 1
  • 1
Highstaker
  • 1,015
  • 2
  • 12
  • 28