#34067: django.core.Paginator wrong query slicing
-------------------------------------+-------------------------------------
     Reporter:  Hristo Trendafilov   |                    Owner:  nobody
         Type:  Bug                  |                   Status:  closed
    Component:  Core (Other)         |                  Version:  3.2
     Severity:  Normal               |               Resolution:  needsinfo
     Keywords:                       |             Triage Stage:
  Paginator,slice,queryset           |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------

Old description:

> A have a ListView defined like so:
>
> {{{
> class AllPracticesListView(LoginRequiredMixin, PermissionRequiredMixin,
> ListView, ToolBoxFunctions):
>     template_name = 'practice_list.html'
>     model = Practice
>     paginate_by = 6
>     permission_required = 'customauth.access_practices'
>
>     def get_queryset(self):
>         qs = self.get_all_practices_by_user().order_by(
>             'company_branch__pk',
> 'practice_profile__personal_profile__last_name').prefetch_related('practice_profile')
>
>         # method < get_all_practices_by_user > is a toolbox method that
> returns:
>         #
> Practice.objects.filter(company_branch__owner=self.request.user).order_by('pk')
>
>         return qs
>
> }}}
>
> Models are defined like so:
> {{{
>
>  class Practice(models.Model):
>                 company_branch = models.ForeignKey(
>                          CompanyBranch,
>                          on_delete=models.PROTECT,
>                          related_name='practices',
>                     )
>                 # CompanyBranch model has an owner field which ForeignKey
> to the user model
>
>                 practice_profile = models.ForeignKey(
>                     PracticeProfile,
>                     on_delete=models.PROTECT,
>                     related_name='practices',
>                 )
>
> class PracticeProfile(models.Model):
>                     personal_profile = models.ForeignKey(
>                         PersonalProfile,
>                         on_delete=models.PROTECT,
>                         blank=True,
>                         null=True,
>                     )
>                     # PersonalProfile model has a field called <
> last_name >
> }}}
> Or schematically:
> {{{
> Practice object relations:
>       -> CompanyBranch
>       -> PracticeProfile
>           -> PersonalProfile /*NULLABLE RELATION/
>
> }}}
>
> When the code is run, the view does not display results correctly.
>
> I did like so to get the WRONG result:
> Added a breakpoint on  {{{Paginator._get_page}}} return statement
>
> Queryset is passed okay and is available in
> {{{Paginator.object_list}}}
>
> But in the args of {{{Paginator._get_page}}} the queryset is totally
> different than expected / should be a slice from the first six elements
> of {{{Paginator.object_list}}} /
>
> I have tried to add a breakpoint like so
> [[Image(https://imgur.com/SdaQUt6)]]
> Then I get this result [[Image(https://imgur.com/5zzLNV0)]].
>
> As you can see, PKs 1632, 1624, etc. are missing, objects are
> different/marked red and purple/, and are actually removed and never
> shown in the view.
>
> If you run slice manually at this point - everything is again fine
> [[Image(https://imgur.com/yvn8KMO)]]
> This happens only on NULL PersonalProfile objects.
>

> I did like so to get OKAY results:
>
> 1. Added a simple breakpoint is added on {{{Paginator.page}}} like so
> [[Image(https://imgur.com/d7J5BMZ)]] and that breakpoint is just run then
> the result is okay [[Image(https://imgur.com/ILDHAMN)]]
>
> 2. changed paginate_by to 10
>
> 3. changed {{{order_by}}} in {{{get_queryset}}} to {{{-pk}}}
>
> 4. call again the {{{page = paginator.page(page_number)}}}
>
> P.S. That is also happening in django 2.2

New description:

 A have a ListView defined like so:

 {{{
 class AllPracticesListView(LoginRequiredMixin, PermissionRequiredMixin,
 ListView, ToolBoxFunctions):
     template_name = 'practice_list.html'
     model = Practice
     paginate_by = 6
     permission_required = 'customauth.access_practices'

     def get_queryset(self):
         qs = self.get_all_practices_by_user().order_by(
             'company_branch__pk',
 
'practice_profile__personal_profile__last_name').prefetch_related('practice_profile')

         # method < get_all_practices_by_user > is a toolbox method that
 returns:
         #
 Practice.objects.filter(company_branch__owner=self.request.user).order_by('pk')

         return qs

 }}}

 Models are defined like so:
 {{{

  class Practice(models.Model):
                 company_branch = models.ForeignKey(
                          CompanyBranch,
                          on_delete=models.PROTECT,
                          related_name='practices',
                     )
                 # CompanyBranch model has an owner field which ForeignKey
 to the user model

                 practice_profile = models.ForeignKey(
                     PracticeProfile,
                     on_delete=models.PROTECT,
                     related_name='practices',
                 )

 class PracticeProfile(models.Model):
                     personal_profile = models.ForeignKey(
                         PersonalProfile,
                         on_delete=models.PROTECT,
                         blank=True,
                         null=True,
                     )
                     # PersonalProfile model has a field called < last_name
 >
 }}}
 Or schematically:
 {{{
 Practice object relations:
       -> CompanyBranch
       -> PracticeProfile
           -> PersonalProfile /*NULLABLE RELATION/

 }}}

 When the code is run, the view does not display results correctly.

 I did like so to get the WRONG result:
 Added a breakpoint on  {{{Paginator._get_page}}} return statement

 Queryset is passed okay and is available in
 {{{Paginator.object_list}}}

 But in the args of {{{Paginator._get_page}}} the queryset is totally
 different than expected / should be a slice from the first six elements of
 {{{Paginator.object_list}}} /

 I have added a breakpoint like so [[Image(https://imgur.com/SdaQUt6)]]. I
 do not use the method itself, just stopped the execution to check what
 data the `Page` class itself is called with.

 Then I get this result [[Image(https://imgur.com/5zzLNV0)]].

 As you can see, PKs 1632, 1624, etc. are missing, objects are
 different/marked red and purple/, and are actually removed and never shown
 in the view.

 If you run slice manually at this point - everything is again fine
 [[Image(https://imgur.com/yvn8KMO)]]
 This happens only on NULL PersonalProfile objects.


 I did like so to get OKAY results:

 1. Added a simple breakpoint is added on {{{Paginator.page}}} like so
 [[Image(https://imgur.com/d7J5BMZ)]] and that breakpoint is just run then
 the result is okay [[Image(https://imgur.com/ILDHAMN)]]

 2. changed paginate_by to 10

 3. changed {{{order_by}}} in {{{get_queryset}}} to {{{-pk}}}

 4. call again the {{{page = paginator.page(page_number)}}}

 P.S. That is also happening in django 2.2

--

Comment (by Hristo Trendafilov):

 Replying to [comment:2 Mariusz Felisiak]:
 > Thanks for the report, however `Paginator` works for me. I'm also not
 sure why you're using `_get_page()` which is a private undocumented API. I
 don't think you've explained the issue in enough detail to confirm a bug
 in Django. Please reopen the ticket if you can debug your issue and
 provide details about why and where Django is at fault. If you're having
 trouble in debugging, see TicketClosingReasons/UseSupportChannels for ways
 to get help.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34067#comment:3>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/01070183936f41ae-7653fae7-843f-4a67-a1da-c59afcfb2900-000000%40eu-central-1.amazonses.com.

Reply via email to