Django pagination (получить номер страницы, соответствующий объекту) - PullRequest
4 голосов
/ 13 декабря 2010

У меня есть страница, я пытаюсь получить страницу индекса со страницы объекта (сортировка по страницам в обратном порядке)

get_paginated_posts возвращает paginator для модели Post:

class PostManager(models.Manager):
    def get_paginated_posts(self, request=None):
        if request and request.user.has_perm('blog.change_post'):
            posts = super(PostManager, self).filter(is_update=False)
        else:        
            posts = super(PostManager, self).filter(publish=True, is_update=False)
        return Paginator(posts, POSTS_PER_PAGE)
    .
    .

Это моя модель

class Post(models.Model):
    .
    .
    .
    def get_page(self, request=None):
        paginator = Post.objects.get_paginated_posts(request)
        for i in range(1, paginator.num_pages+1):
            if self in paginator.page(i).object_list:                
                return i
            pass
        return False 

Меня беспокоит вызов Post.objects.get_paginated_posts в функции get_page.
Правильно ли вызывать Post класс из экземпляра? Есть ли другой лучший способ сделать это возможно?
Почему я не могу позвонить super(Post, self).objects.get_paginated_posts, чтобы сделать то же самое?
Я понимаю, что self.objects.get_paginated_posts не будет работать из-за отсутствия доступа объекта к его менеджеру.

решаемые

Финальный код, предложенный Томашом Элендтом:

class PostManager(models.Manager):
    def get_paginated_posts(self, user=None):
        if user and user.has_perm('blog.change_post'):
            posts = super(PostManager, self).filter(is_update=False)
        else:        
            posts = super(PostManager, self).filter(publish=True, is_update=False)
        return Paginator(posts, POSTS_PER_PAGE)

class Post(models.Model):
    .
    def get_page(self, request=None):
        return self._default_manager.filter(is_update = False, time__gt=self.time).count()/POSTS_PER_PAGE +1 
        #Just a one line now :P 

1 Ответ

2 голосов
/ 13 декабря 2010

Это не лучшая идея, что вы делаете.Попробуйте представить, на сколько запросов он будет переведен - в худшем случае вам потребуется извлечь все сообщения пользователя из базы данных!

Я предполагаю, что в вашей модели Post есть предопределенный порядок(тот, который Paginator использует).Используйте это, чтобы получить количество сообщений пользователя, которые предшествуют этой конкретной записи сообщения.Если вы разделите это число на значение POSTS_PER_PAGE, вы получите номер своей страницы.

ИМХО, используя PostManager в Post методах - это нормально.Что не хорошо, так это то, что вы передаете объект запроса к нему, в то время как я думаю, что вы должны использовать user_id для этого (и проверка прав доступа должна быть действительно частью логики представления).1014 * пример

from django.db import models
from django.contrib.auth.models import User

POSTS_PER_PAGE = 10

class Post(models.Model):
    """
    >>> from datetime import datetime, timedelta
    >>> from django.db import connection
    >>> from django.conf import settings
    >>>
    >>> user = User.objects.create_user("test", "test@domain.com")
    >>> for i in xrange(100):
    ...     p = Post.objects.create(author=user,
    ...                             pub_date=datetime.now() - timedelta(hours=i))
    >>> post = Post.objects.all()[68]
    >>> settings.DEBUG = True    # monkey-patching settings - ugly
    >>> connection.queries = []  # cleaning previous queries
    >>> post.get_page()
    7
    >>> len(connection.queries)  # print number of queries of `get_page` call
    1
    """
    pub_date = models.DateTimeField(auto_now_add=True)
    author = models.ForeignKey(User)
    class Meta:
        ordering = ["-pub_date"]

    def get_page(self):
        return self._default_manager.filter(author__id=self.author_id).filter(
            pub_date__gt=self.pub_date).count() / POSTS_PER_PAGE + 1
...