2014-04-16 3 views
6

Mam ogólny widok ListCreateAPIView. Zaimplementowałem funkcję get_queryset, która wykonuje wyszukiwanie. Funkcja analizuje zapytanie, wyodrębnia tagi i terminy i zwraca zestaw zapytań.Dodawanie metadanych do filtrowania w środowisku django rest

def get_queryset(self): 
     query = self.request.QUERY_PARAMS.get('query', None) 

     # No deleted items 
     queryset = Items.objects.filter(deleted__isnull=True) 

     if query is None: 
      return queryset 

     predicates = [] 

     # Generate predicates from query  

     queryset = queryset.filter(reduce(__and__,predicates)) 
     return queryset 

Jaki jest najlepszy sposób, aby dodać metadane do odpowiedzi z danymi z funkcją get_queryset?

Szukam czegoś podobnego do sposobu działania stronicowania.

{ 
query : { 
    terms : ['term1','term2'], 
    tags : ['tag1','tag2'] , 
    } 
results : [ 
     { name : 'item1', .... } 
     { name : 'item2', .... } 
    ] 
} 

EDIT

Więc stworzył zwyczaj FilterBackend do filtrowania i teraz mam wystąpienie z wnioskiem i odpowiedzi. Patrząc na kod paginacji dla reszty django widzę, że owija wyniki w serializatorze. Paginacja jest wbudowana w klasę widoku, więc fw wywołuje serializację, jeśli zostanie wykryty paginator. Patrzenie na api wyszukiwania nie przyniosło żadnych nowych pomysłów.

Moje pytanie pozostaje: Jaki jest najlepszy i najmniej inwazyjny sposób dodawania metadanych z serwera filtrów do odpowiedzi?

Jednym ze sposobów, które mogę wymyślić (i jeden, który mi się nie podoba) jest przeciążenie matadata na żądanie w układzie filtrów i przesłonięcie finalize_response w widoku - bez wątpienia najgorszy sposób to zrobić.

Odpowiedz

4

Nie jestem pewien, czy to najlepszy sposób, ale prawdopodobnie zastąpiłbym get po prostu przechwycić obiekt odpowiedzi i zmodyfikować response.data, jak tylko chcesz. Coś tak prostego jak

from rest_framework import generics 

class SomeModelList(generics.ListCreateAPIView): 
    """ 
    API endpoint representing a list of some things. 
    """ 

    model = SomeModel 
    serializer_class = SomeModelSerializer 

    def get(self, request, *args, **kwargs): 
     response = super(SomeModelList, self).get(request, *args, **kwargs) 

     # redefine response.data to include original query params 
     response.data = { 
      'query': dict(request.QUERY_PARAMS), 
      'results': response.data 
     } 

     return response 

Jeśli znalazłeś się powtarzając to dla wielu widokach list można utrzymać się na sucho przy użyciu Mixin i umieścić go w swojej listy klas API:

from rest_framework import generics 
from rest_framework.mixins import ListModelMixin 

class IncludeQueryListMixin(ListModelMixin): 
    def list(self, request, *args, **kwargs): 
     response = super(IncludeQueryListMixin, self).list(request, *args, **kwargs) 

     # redefine response.data to include original query params 
     response.data = { 
      'query': dict(request.QUERY_PARAMS), 
      'results': response.data 
     } 

     return response 


class SomeModelList(IncludeQueryListMixin, generics.ListCreateAPIView): 
    """ 
    API endpoint representing a list of some things. 
    """ 

    model = SomeModel 
    serializer_class = SomeModelSerializer 
+0

Kiedy próbowałem przechwycić obiekt odpowiedzi Mam "ContentNotRenderedError - Treść odpowiedzi musi być renderowana, zanim będzie można uzyskać do niej dostęp." Niestety, myślę, że trzeba zastąpić miejsca, w których jest wywoływana odpowiedź, aby można było zmienić format "danych". –

+0

@MarkChackerian Nie jestem pewien, co spowodowało twój błąd, ale zaktualizowałem swoją odpowiedź, używając pełnego przykładu, który zweryfikowałem do pracy z DRF 2.3.13. Czy możesz ponownie sprawdzić? – Fiver

+0

Ponownie sprawdziłem i potwierdziłem, że twoje rozwiązanie działa. Nadal dostaję błąd podczas próby sprawdzenia obiektu odpowiedzi, ale nie ma takiej potrzeby. –