使用Django的Paginator类和MongoDB游标

时间:2012-04-10 11:22:20

标签: django mongodb pagination pymongo

是否有一种已知的扩展MongoDB游标对象的方法,使其与Django的django.core.paginator.Paginator类兼容?

或者,也许,扩展Django的课程?

2 个答案:

答案 0 :(得分:0)

您的临时解决方案(https://gist.github.com/2351079)看起来不错 - 但不是强制光标使用list()获取所有结果并使用[bottom:top]分页,而是尝试使用显式地在游标上.skip().limit() - 它可能会提高性能。

答案 1 :(得分:0)

我遇到了同样的问题并实施了我自己的Paginator课程。这是代码:

<table>
    <tr>
        <td>id</td>
        <td>name</td>
        <td>type</td>
    </tr>
    <?php 
    $i = 0;
    foreach($data as $key => $value) {
        $i++;
        ?>
    <tr>
        <td><?php echo $i; ?></td>
        <td><?php echo $key; ?></td>
        <td><?php echo $value; ?></td>
    </tr>
    <?php } ?>
</table>

主要变化是:

  • 每个页面都应该获得游标的克隆,因为每个游标的切片只能工作一次
  • 每个页面也应该直接将其转换为列表,以便len()正常工作

这是一个在视图中使用它的辅助函数:

from django.core.paginator import Paginator, Page

class MongoPaginator(Paginator):
    """
    Custom subclass of Django's Paginator to work with Mongo cursors.
    """
    def _get_page(self, *args, **kwargs):
        """
        Returns an instance of a single page. Replaced with our custom
        MongoPage class.
        """
        return MongoPage(*args, **kwargs)

    def page(self, number):
        """
        Returns a Page object for the given 1-based page number.
        Important difference to standard Paginator: Creates a clone of the
        cursor so we can get multiple slices.
        """
        number = self.validate_number(number)
        bottom = (number - 1) * self.per_page
        top = bottom + self.per_page
        if top + self.orphans >= self.count:
            top = self.count
        return self._get_page(
            self.object_list.clone()[bottom:top], number, self
        )

class MongoPage(Page):
    """
    Custom Page class for our MongoPaginator. Just makes sure the cursor is
    directly converted to list so that we can use len(object_list).
    """
    def __init__(self, object_list, number, paginator):
        self.object_list = list(object_list)
        self.number = number
        self.paginator = paginator

然后你可以这样做:

def get_paginated_cursor(request, cursor, per_page=25, param='page'):
    """
    Helper to deal with some standard pagination. Pass a request and a
    cursor and it will return a paginated version of it.
    """
    paginator = MongoPaginator(cursor, per_page)

    page = request.GET.get(param, 1)
    try:
        cursor = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer, deliver first page.
        cursor = paginator.page(1)
    except EmptyPage:
        # If page is out of range (e.g. 9999), deliver last page of results.
        cursor = paginator.page(paginator.num_pages)

    return cursor