Django: производительность базы данных ListView с разбивкой на страницы

У меня есть ListView с нумерацией страниц:

class StoriesListView(ListView):
    model = Story
    paginate_by = 20

    def get_queryset(self):
        return Story.objects.all().order_by('-updated_at')

У меня есть 1000 Story объектов в базе данных. Что происходит, когда пользователь загружает мое представление? Будут ли запрашиваться все 1000 из базы данных или только 20? Как я могу оптимизировать это?


person netimen    schedule 12.10.2013    source источник


Ответы (4)


это зависит от того, как вы его используете. Объекты QuerySet являются ленивыми, и в этом В конкретном случае запрос sql добавит LIMIT и OFFSET, поэтому запрос всегда будет возвращать только 20 результатов. Но когда вы хотите использовать, например, связанные объекты в своем шаблоне, вы должны оптимизировать свой запрос с помощью методов select_related или prefetch_related.

Я думаю, вам следует прочитать, как оптимизировать доступ к базе данных в среде django.

Надеюсь это поможет.

person dydek    schedule 12.10.2013

Класс Paginator принимает возвращаемое значение get_queryset (т. е. весь набор запросов в данном случае) и объединяет его, чтобы предоставить вам доступ только к 20. Он должен работать со всем набором запросов, иначе вы не сможете использовать его для отображения список страниц, например.

Вы можете следить за кодом, чтобы увидеть его в действии:

get() > get_context_data() > paginate_queryset() > Paginator.init()

Это означает, что в контексте вашего шаблона , переменная queryset представляет собой весь набор запросов. Переменная page используется для получения только тех объектов, которые принадлежат текущей странице. Это делается путем объединения исходного набора запросов, который оценит его и попадет в БД. Вы можете перебирать объекты на этой странице: {% for object in page %} и это больше не попадет в базу данных:

# https://github.com/django/django/blob/master/django/core/paginator.py#L119
def __getitem__(self, index):
    if not isinstance(index, (slice,) + six.integer_types):
        raise TypeError
    # The object_list is converted to a list so that if it was a QuerySet
    # it won't be a database hit per __getitem__.
    if not isinstance(self.object_list, list):
        self.object_list = list(self.object_list)
    return self.object_list[index]
person Timmy O'Mahony    schedule 12.10.2013

Он получит только 20 объектов. Paginator принимает результат метода get_queryset в качестве начального набора запросов, и он попадет в базу данных только при повторении, так что все в порядке. get_queryset метод не затрагивает саму базу данных.

person mariodev    schedule 12.10.2013

Та же проблема, с которой я столкнулся во время разбивки на страницы. Для нумерации страниц вам не нужно делать функцию внутри модальной.

вы можете использовать LIMIT так же, как и с помощью простой моей функции обобщения

def test Пагинация (запрос):

dataObj             = paginationData('Item',page_no,10)
data["dataIndex"]   = dataObj["dataIndex"]
data["page_no"]     = dataObj["page_no"] #given page number will helps to active link at template
data["data"]        = dataObj["data"]  #actual data will helps in template
data['pagination']  = dataObj["pagination"] #Will helps to make dynamic link for pagination

ОБОБЩАЯ ФУНКЦИЯ РАЗБИВКИ НА СТРАНИЦЫ

def paginationData(modalName,pageNo,perPage):
    data = {} #initialize variables
    Modal = getModel(modalName) # Function to get modal reference
    count = Modal.objects.count()#Calculate no of records
    no_of_record_per_page = ceil(float(count) / perPage)
    print ",Records counts : " + str(no_of_record_per_page)
    pages = [] #No of pages
    pages.append(1) 
    a = 1
    while a < (no_of_record_per_page):
        a += 1 # Same as a = a + 1
        pages.append(a)
    data["pagination"] = pages # pagenation for display link of page
    data["page_no"] = pageNo
    data['data'] = Modal.objects.all()[((pageNo-1)*perPage):(pageNo*perPage)]
    data['dataIndex'] = str((pageNo -1)*perPage) 
    return data
person Roni    schedule 12.10.2013