16

Ho appena aggiornato Django Rest Framework 3.1 e sembra che si sia scatenato l'inferno.Django Rest Framework 3.1 interruzioni pagination.PaginationSerializer

nel mio serializers.py stavo avendo il seguente codice:

class TaskSerializer(serializers.ModelSerializer): 
    class Meta: 
    model = task 
    exclude = ('key', ...) 

class PaginatedTaskSerializer(pagination.PaginationSerializer): 
    class Meta: 
     object_serializer_class = TaskSerializer 

che stava lavorando bene. Ora con il rilascio di 3.1 non riesco a trovare esempi su come fare la stessa cosa dal PaginationSerializer non c'è più. Ho provato a sottoclasse PageNumberPagination e utilizzo i suoi metodi predefiniti paginate_queryset e get_paginated_response ma non riesco più a ottenere i risultati serializzati.

In altre parole il mio problema è che non riesco più a fare questo:

class Meta: 
    object_serializer_class = TaskSerializer 

Tutte le idee?

Grazie in anticipo

+1

Mi sono appena imbattuto in questo stesso identico problema. Ho deciso di aggiornare tutti i miei pacchetti e questa è stata l'unica cosa che si è rotta. Spero che questo risponda perché non ho trovato nulla neanche io. – Brobin

+0

"Ho appena aggiornato Django Rest Framework 3.1 e sembra che si sia scatenato l'inferno." Lol. – jmoz

risposta

10

non sono sicuro se questo è il modo del tutto corretto per farlo, ma funziona per le mie esigenze. Usa Django Paginator e un serializzatore personalizzato.

Qui è la mia Visualizzazione classi che recupera gli oggetti per la serializzazione

class CourseListView(AuthView): 
    def get(self, request, format=None): 
     """ 
     Returns a JSON response with a listing of course objects 
     """ 
     courses = Course.objects.order_by('name').all() 
     serializer = PaginatedCourseSerializer(courses, request, 25) 
     return Response(serializer.data) 

Ecco il hacked insieme Serializzatore che usa il mio serializzatore Course.

from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage 

class PaginatedCourseSerializer(): 
    def __init__(self, courses, request, num): 
     paginator = Paginator(courses, num) 
     page = request.QUERY_PARAMS.get('page') 
     try: 
      courses = paginator.page(page) 
     except PageNotAnInteger: 
      courses = paginator.page(1) 
     except EmptyPage: 
      courses = paginator.page(paginator.num_pages) 
     count = paginator.count 

     previous = None if not courses.has_previous() else courses.previous_page_number() 
     next = None if not courses.has_next() else courses.next_page_number() 
     serializer = CourseSerializer(courses, many=True) 
     self.data = {'count':count,'previous':previous, 
       'next':next,'courses':serializer.data} 

Questo mi dà un risultato che è simile al comportamento che il vecchio cercapersone ha dato.

{ 
    "previous": 1, 
    "next": 3, 
    "courses": [...], 
    "count": 384 
} 

Spero che questo aiuti. Penso ancora che ci sia un modo migliore per farlo con la nuova API, ma non è documentato bene. Se capisco qualcosa di più, modifico il mio post.

EDIT

Credo di aver trovato un modo migliore e più elegante per farlo bey creare il mio paginator personalizzato per ottenere un comportamento come ho usato per ottenere con la vecchia classe impaginato Serializer.

Questa è una classe di impaginatore personalizzata. Ho sovraccaricato la risposta e i metodi della pagina successiva per ottenere il risultato desiderato (ad esempio ?page=2 anziché l'URL completo).

from rest_framework.response import Response 
from rest_framework.utils.urls import replace_query_param 

class CustomCoursePaginator(pagination.PageNumberPagination): 
    def get_paginated_response(self, data): 
     return Response({'count': self.page.paginator.count, 
         'next': self.get_next_link(), 
         'previous': self.get_previous_link(), 
         'courses': data}) 

    def get_next_link(self): 
     if not self.page.has_next(): 
      return None 
     page_number = self.page.next_page_number() 
     return replace_query_param('', self.page_query_param, page_number) 

    def get_previous_link(self): 
     if not self.page.has_previous(): 
      return None 
     page_number = self.page.previous_page_number() 
     return replace_query_param('', self.page_query_param, page_number) 

Poi mio punto di vista, naturalmente, è molto simile a come è stato implementato esso, solo questa volta usando il Paginator personalizzato.

class CourseListView(AuthView): 
    def get(self, request, format=None): 
     """ 
     Returns a JSON response with a listing of course objects 
     """ 
     courses = Course.objects.order_by('name').all() 
     paginator = CustomCoursePaginator() 
     result_page = paginator.paginate_queryset(courses, request) 
     serializer = CourseSerializer(result_page, many=True) 
     return paginator.get_paginated_response(serializer.data) 

Ora ho ottenuto il risultato che sto cercando.

{ 
    "count": 384, 
    "next": "?page=3", 
    "previous": "?page=1", 
    "courses": [] 
} 

io non sono ancora sicuro di come questo funziona per l'API sfogliabile (io non uso questa funzione di DRF). Penso che tu possa anche creare la tua classe personalizzata per questo. Spero che aiuti!

+0

Sì. La tua soluzione funziona. Non è ancora ottimale in quanto non possiamo ottenere collegamenti di paginazione sull'API navigabile (e gli hyperlink di impaginazione sono spariti), ma attualmente è l'unico che funziona. Dovremmo essere molto vicini ora. Fammi sapere se ti viene in mente qualcosa di meglio altrimenti accetterò la tua risposta tra un paio di giorni. Grazie ancora. – kstratis

+0

Anche questo è corretto. Ora possiamo fare praticamente qualsiasi cosa ..! Credo che la chiave della soluzione sia stata la sostituzione di 'class Meta: object_serializer_class = CourseSerializer' con un semplice costruttore' serializer = CourseSerializer (courses, many = True) '. Passato quel punto possiamo lasciare che la nostra immaginazione prenda il sopravvento. Ad ogni modo, preferisco attenermi alle impostazioni predefinite, ma dato che mi hai dato la "chiave", accetto la tua risposta. Grazie. – kstratis

20

penso ho capito (per la maggior parte, almeno):

Quello che abbiamo dovuto usare fin dall'inizio è questo:

Basta usare il built-in paginator e cambiare il vostro views.py a questo:

from rest_framework.pagination import PageNumberPagination 

class CourseListView(AuthView): 
    def get(self, request, format=None): 
     """ 
     Returns a JSON response with a listing of course objects 
     """ 
     courses = Course.objects.order_by('name').all() 
     paginator = PageNumberPagination() 
     # From the docs: 
     # The paginate_queryset method is passed the initial queryset 
     # and should return an iterable object that contains only the 
     # data in the requested page. 
     result_page = paginator.paginate_queryset(courses, request) 
     # Now we just have to serialize the data just like you suggested. 
     serializer = CourseSerializer(result_page, many=True) 
     # From the docs: 
     # The get_paginated_response method is passed the serialized page 
     # data and should return a Response instance. 
     return paginator.get_paginated_response(serializer.data) 

per il formato pagina desiderato è sufficiente impostare la PAGE_SIZE in settings.py:

REST_FRAMEWORK = { 
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 
    'PAGE_SIZE': 15 
} 

Si dovrebbe essere tutti impostati ora con tutte le opzioni presenti nel corpo della risposta (conteggio, collegamenti successivi e posteriori) ordinati esattamente come prima dell'aggiornamento.

Tuttavia c'è ancora una cosa che mi turba ancora: Dobbiamo anche essere in grado di ottenere il nuovo html pagination controls che per qualche motivo sono assenti per il momento ...

ho potuto sicuramente utilizzare un altro paio di suggerimenti su questo ...

+2

Wow. è davvero così semplice? Dovrebbero davvero aggiornare la documentazione con un esempio. Per quanto riguarda i link HTML, non lo so, non ho mai veramente usato l'API navigabile. – Brobin

+2

cool! questa soluzione mi ha risparmiato così tanto tempo a controllare il loro codice sorgente. Spero che facciano il documento al più presto. – haudoing

+0

@haudoing: crea i documenti che desideri vedere nel mondo! È open source e i documenti sono un ottimo modo per restituire. – mlissner

0

Mi rendo conto che è passato più di un anno da quando questo è stato pubblicato ma sperando che questo aiuti gli altri. La risposta alla mia domanda simile è stata la soluzione per me. Sto usando DRF 3.2.3.

Django Rest Framework 3.2.3 pagination not working for generics.ListCreateAPIView

Vedendo come è stato implementato mi ha dato la soluzione necessaria per ottenere l'impaginazione + i controlli nella API visibile.

https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/mixins.py#L39

Problemi correlati