I have a paginate I am trying to get the index page from an object page (sort of pagination in reverse)
The get_paginated_posts returns a paginator for the model 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)
.
.
This is my model
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
My concern is the Post.objects.get_paginated_posts
call in the get_page function.
Is it right to call Post
class from an instance? Is there any other better way to do this possible?
Why cannot I call super(Post, self).objects.get_paginated_posts
to do the same?
I understand that self.objects.get_paginated_posts
wont work because of absent access for the object to its manager.
Solved
Final code as suggested by Tomasz Elendt:
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
It's not the best idea what you're doing. Try to imagine how many queries it'll be translated to -- in the worst case you'd need to retrieve all user's posts from database!
I assume that you have some predefined ordering in your Post
model (the one that Paginator
uses). Use that to obtain the number of user's posts that precede that specific post record. If you divide that number by the POSTS_PER_PAGE
value you'll get your page number.
IMHO using PostManager
in Post
methods is ok. What's not ok is that you're passing request object to it while I think you should use user_id
for that (and permission checking should be really part of a view logic).
EDIT: example
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
来源:https://stackoverflow.com/questions/4429331/django-pagination-get-page-no-corresponding-to-the-object