3

Ich benutze Django Rest Framework. Hier ist mein Code:Django Rest erforderliche Parameter in URL

urls.py:

urlpatterns = [ 
    url(r'^users/show', UserShow.as_view()), 
] 

view.py:

class UserShow(ListAPIView): 
    queryset = User.objects.all() 
    serializer_class = UserSerializer 

    def get_queryset(self): 
     queryset = User.objects.all() 
     username = self.request.query_params.get('username', None) 
     user_id = self.request.query_params.get('user_id', None) 
     if username is not None: 
      queryset = queryset.filter(username=username) 
     if user_id is not None: 
      queryset = queryset.filter(pk=user_id) 
     return queryset 

Ich möchte wie diese Werte von der URL erhalten: /users/show?user_id=1 oder /users/show?username=mike .

Entweder muss ein user_id oder username Parameter erforderlich sein. Wie kann ich es in klassenbasierten Ansichten steuern?

Mit meinem Code, wenn ich die Anfrage mit falschem Parameternamen senden /users/show?user111name=mike oder einfach /users/show die Ansicht der Kursantwort mich mit queryset = User.objects.all() und listet alle Benutzer auf. Ich brauche das nicht. Ich muss bei Bedarf Parameter None Reaktion mit 404.

sind, kann ich mit Funktion basiert Ansicht benötigt Ergebnis:

@api_view(['GET']) 
def users(request): 
    if request.method == 'GET': 
     queryset = User.objects.all() 
     username = request.GET.get('username', None) 
     user_id = request.GET.get('user_id', None) 

     if username is not None: 
      queryset = queryset.filter(username=username) 
     elif user_id is not None: 
      queryset = queryset.filter(pk=user_id) 
     else: 
      return Response({"status": "required field not found."}, 
          status=status.HTTP_404_NOT_FOUND) 

     if not queryset.exists(): 
      return Response({"status": "not found."}, 
          status=status.HTTP_404_NOT_FOUND) 

     serializer = UserSerializer(queryset, many=True) 
     return Response(serializer.data) 

Aber wie kann ich es tun mit generic Klasse basierte Ansichten?

+0

Sie sind http://stackoverflow.com/questions/36505792/drf-base-viewset-for-abfrage-param-validierung – trinchet

+0

Könnten Sie mir bitte erklären, warum Sie ListAPIView verwenden, um * single * object zu bekommen? Es gibt eine RetrieveAPIView, die für eine solche Verwendung dediziert ist, und Sie können den Benutzernamen oder die ID als Teil der URL verwenden, die nicht abgefragt wird. – Jerzyk

Antwort

0
class UserIdRetrieve(RetrieveAPIView): 
    queryset = User.objects.all() 
    serializer_class = UserSerializer 

class UserUsernameRetrieve(UserIdRetrieve): 
    lookup_field = 'username' 

und in Urls:

class UserIdRetrieve(RetrieveAPIView): 
    queryset = User.objects.all() 
    serializer_class = UserSerializer 

    def get_object(self): 
     queryset = self.filter_queryset(self.get_queryset()) 

     if 'username' in self.request.query_params: 
      filter_kwargs = {'username': self.request.query_params['username']} 
     elif 'user_id' in self.request.query_params: 
      filter_kwargs = {'id': self.request.query_params['user_id']} 
     else: 
      raise Http404('Missing required parameters') 

     obj = get_object_or_404(queryset, **filter_kwargs) 

     # May raise a permission denied 
     self.check_object_permissions(self.request, obj) 

     return obj 

und in Urls:

urlpatterns = [ 
    url(r'^users/show', UserRetrieve.as_view()) 
] 

urlpatterns = [ 
    url(r'^users/(?P<pk>\d+)/', UserIdRetrieve.as_view()), 
    url(r'^users/by-username/(?P<username>\w+)/', UserUsernameRetrieve.as_view()) 
] 

, wenn Ihre URL-Struktur über ein Muss, kleine Änderung ist

+0

Ich benutze 'ListAPIView', weil' RetrieveAPIView' 'pk' als Argument benötigt, aber in meinem Fall bekomme ich es nicht von der URL im klassischen django Weg, da' query_params verwendet wird '. Natürlich wird Ihre Variante funktionieren, aber sehen Sie sich das benötigte URL-Format noch einmal an, es ist nicht genau das, was ich brauche. – arstj

+0

hinzugefügt Version, die Ihre URL-Struktur entspricht – Jerzyk

-1
class UserShow(ListAPIView): 

    queryset = User.objects.all() 
    serializer_class = UserSerializer 

    def filter_queryset(self, queryset): 
     username = self.request.query_params.get('username', None) 
     user_id = self.request.query_params.get('user_id', None) 

     if username is not None: 
      queryset = queryset.filter(username=username) 
     if user_id is not None: 
      queryset = queryset.filter(pk=user_id) 
     return queryset 

    def list(self,request,*args,**kwargs): 
     username = self.request.query_params.get('username', None) 
     user_id = self.request.query_params.get('user_id', None) 
     if not (username or user_id): 
      return Response({"status": "Required field not found."}, 
             status=status.HTTP_404_NOT_FOUND) 
     return super(UserShow, self).list(request,*args,**kwargs) 
+0

Es funktioniert, aber gibt es mehr DRY? Jedenfalls markiere ich deine Antwort als Lösung für den Moment. – arstj

+0

ListAPIView sollte nicht zum Abrufen einzelner Instanzen verwendet werden. – Jerzyk

Verwandte Themen