[PYTHON] Django REST Framework Ein wenig nützlich zu wissen.

Ich habe die Elemente, die ich persönlich als Memo aufbewahren möchte, in den Inhalten zusammengefasst, die ich unter Verwendung des REST-Frameworks von Django untersucht habe. Wenn Sie nachschlagen, finden Sie die alltäglichen Inhalte und die Elemente, die Sie selbst implementiert haben. Wenn Sie im Inhalt dieses Artikels Vorschläge haben, dass es einen besseren Weg gibt oder dass es falsch ist, sich einem solchen Problem überhaupt zu stellen, hinterlassen Sie bitte einen Kommentar.

Ich möchte eine verschachtelte URL ausdrücken

Es ist einfach, eine solche Rest-API mit dem Restframework-Router zu erstellen.

/api/v1/groups/ GET POST
/api/v1/groups/1/ GET PUT PATCH DELETE
/api/v1/members/ GET POST
/api/v1/members/1/ GET PUT PATCH DELETE

Es ist jedoch schwierig, eine API mit verschachtelten URLs mit dem Rest-Framework-Router zu erstellen, wie unten gezeigt.

/api/v1/groups/ GET POST
/api/v1/groups/1/ GET PUT PATCH DELETE
/api/v1/groups/1/members/ GET POST
/api/v1/groups/1/members/1/ GET PUT PATCH DELETE

Lösungen

Die Lösung besteht darin, drf-verschachtelte Router zu verwenden. drf-nested-routers ist eine Bibliothek, mit der Sie verschachtelte URLs einfach im Rest-Framework implementieren können.

Einführungsmethode

Führen Sie eine Pip-Installation durch.

$ pip install drf-nested-routers

Implementierung

# urls.py

from rest_framework_nested import routers
from .views import *

router = routers.SimpleRouter()

router.register(r'groups', GroupViewSet)
groups_router = routers.NestedSimpleRouter(router, r'groups', lookup='group')
groups_router.register(r'members', MemberViewSet, base_name='groups-members')

urlpatterns = [
	url(r'^api/v1/', include(router.urls)),
	url(r'^api/v1/', include(groups_router.urls)),
]

Sie können jeden Primärschlüssel mit dem folgenden Argument abrufen. Der Schlüsselwortname des Arguments ist der in urls.py angegebene Suchname + _pk.

# views.py
class GroupViewSet(viewsets.ViewSet):
    def list(self, request):
        (...)
        return Response(serializer.data)

    def retrieve(self, request, pk=None):
        group = self.queryset.get(pk=pk)
        (...)
        return Response(serializer.data)


class MemberViewSet(viewsets.ViewSet):
    def list(self, request, group_pk=None):
        members = self.queryset.filter(group=group_pk)
        (...)
        return Response(serializer.data)

    def retrieve(self, request, pk=None, group_pk=None):
        member = self.queryset.get(pk=pk, group=group_pk)
        (...)
        return Response(serializer.data)

Ich möchte mehrere Modelle gleichzeitig mit dem von ModelViewSet implementierten POST der REST-API erstellen

Tatsächlich können Sie mit der Methode create () von standard views.ModelViewSet nicht mehrere Modelle gleichzeitig erstellen. Wenn Sie mehrere Modelle erstellen möchten, müssen Sie die API entsprechend drücken.

Lösungen

Code erstellt

Daher habe ich einen Dekorateur erstellt, der ein einzelnes Modell oder mehrere Modelle mit views.ModelViewSet erstellen kann.

Kopieren Sie den folgenden Code und speichern Sie ihn in einer geeigneten Datei.

from rest_framework.response import Response
from rest_framework import status

def multi_create(serializer_class=None):
    def __multi_create(function):
        def __wrapper(self, request, *args, **kwargs):
            many = False
            if isinstance(request.data, list):
                many = True
            serializer = serializer_class(data=request.data, many=many)
            if serializer.is_valid():
                serializer.save()
                headers = self.get_success_headers(serializer.data)
                data = serializer.data
                result = function(self, request, *args, **kwargs)
                if result is not None:
                    return result
                if many:
                    data = list(data)
                return Response(data,
                                status=status.HTTP_201_CREATED,
                                headers=headers)
            else:
                return Response(serializer.errors,
                                status=status.HTTP_400_BAD_REQUEST)
        return __wrapper
    return __multi_create

Wie benutzt man

Importieren Sie den multi_create-Dekorator aus der zuvor gespeicherten Datei und hängen Sie ihn wie unten gezeigt an die create () -Methode von ViewSet an. Das Argument ist die Serializer-Klasse, die dem Modell entspricht, das Sie erstellen möchten.

# views.py

from .decorators import multi_create

class MyViewSet(viewsets.ModelViewSet):
    queryset = MyModel.objects.all()
    serializer_class = MySerializer
  
	@multi_create(serializer_class=MySerializer)
    def create(self, request):
        pass

Sie müssen lediglich die folgenden JSON-Daten im Listenformat POSTEN.

[
	{"name": "hoge"},
	{"name": "fuga"}
]

Die folgende Antwort wird zurückgegeben.

[
	{
		"id": 1,
		"name": "hoge"
	},
	{
		"id": 2,
		"name": "fuga"
	}
]

Ich möchte den Feldwert von Serializer dynamisch bestimmen

Möglicherweise möchten Sie die Feldwerte für den Serializer dynamisch ermitteln.

Lösung

Dieses Mal werden wir serializers.SerializerMethodField () verwenden. Mit serializers.SerializerMethodField () können Sie den Wert des Felds anhand des Ergebnisses der Methode ermitteln.

Angenommen, Sie haben eine Modellklasse wie die folgende und eine hoge () -Methode, die name + _hoge zurückgibt.

# modles.py
class MyModel(models.Model):
    name = models.CharField(max_length=100)
    
    def hoge(self):
        return "{}_hoge".format(self.name)

In Serializer wird der Wert des Wertefelds dynamisch bestimmt, indem Serializer angegeben werden. SerializerMethodField () wie unten gezeigt. Der angewendete Methodenname lautet get_ + Feldname. Diesmal ist der Rückgabewert der Methode get_value () der Wert. Es ist auch möglich, den angewendeten Methodennamen mit dem Argument method_name von SerializerMethodField () anzugeben.

# serializer.py
class MySerializer(serializers.ModelSerializer):
    value = serializers.SerializerMethodField()
    
    class Meta:
        model = MyModel
    
    def get_value(self, obj):
        return obj.hoge()

Ich möchte einen Fehler, der in Model oder Selializer aufgetreten ist, als Antwort zurückgeben

Angenommen, die API wird getroffen und die create () -Methode des ViewSet wird aufgerufen. Wie kann ich zu diesem Zeitpunkt eine Fehlerantwort geben, wenn in der save () -Methode der Model-Klasse ein Fehler auftritt (siehe unten)? Es gibt keine Methode, die ich in der MyViewSet-Klasse für die Fehlerbehandlung mit try außer implementiert habe, und die save () -Methode von MyModel wird vollständig in der Black Box aufgerufen.

# views.py
class MyViewSet(viewsets.ModelViewSet):
    queryset = MyModel.objects.all()
    serializer_class = MySerializer
# models.py
class MyModel(models.Model):
    name = models.CharField(max_length=100)

    def save(self, force_insert=False, force_update=False,
             using=None, update_fields=None):
        if self.hoge():
            raise HogeError('hoge error.')
        super(MyModel, self).save(*args, **kwargs)

    def hoge():
        (...)

Lösungen

Zuerst

Eine Lösung besteht darin, die create () -Methode für die Fehlerbehandlung wie unten gezeigt zu überschreiben.

# views.py
class MyViewSet(viewsets.ModelViewSet):
    queryset = MyModel.objects.all()
    serializer_class = MySerializer

    def create(self, request):
        try:
           super(MyViewSet, self).create(*args, **kwargs) 
        except HogeError:
            (....)
            return Response(content, status=status.HTTP_400_BAD_REQUEST)

    def update(self, request):
        try:
           super(MyViewSet, self).update(*args, **kwargs) 
        except HogeError:
            (....)
            return Response(content, status=status.HTTP_400_BAD_REQUEST)

Bei dieser Methode ist es erforderlich, Fehler beim Erstellen und Aktualisieren auf die gleiche Weise zu behandeln.

Zweite

Eine andere Lösung besteht darin, die handle_exception () -Methode zu überschreiben. handle_exception ist eine Standardmethode für das Rest-Framework, die Fehler behandelt. Wenn Sie beispielsweise eine nicht autorisierte HTTP-Methode treffen, wird eine Antwort zurückgegeben, die der folgenden ähnelt:

HTTP/1.1 405 Method Not Allowed
Content-Type: application/json
Content-Length: 42

{"detail": "Method 'DELETE' not allowed."}

Bei dieser Methode werden Fehler, die von handler_exception nicht ausgeschlossen werden, am Überschreibungsziel ausgeschlossen.

# views.py
class MyViewSet(viewsets.ModelViewSet):
    queryset = MyModel.objects.all()
    serializer_class = MySerializer

    def handle_exception(self, exc):
        try:
            return super(MyViewSet, self).handle_exception(exc)
        except HogeError:
            content = {'detail': '{}'.format(exc.args)}
            return Response(content, status=status.HTTP_400_BAD_REQUEST)

Mit dieser Methode können Sie alle Fehler behandeln, die in diesem MyViewSet auftreten. Übrigens gibt es kein Problem mit der Methode zur Bestimmung des exc-Typs anhand der Instanz anstelle von try Except.

Dritte

Die dritte Methode ist die Verwendung von custom_exception_handler ().

Beschreiben des Pfads von custom_exception_handler, der in settings.py implementiert werden soll.

# settings.py
REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'
}

Implementieren Sie custom_exception_handler () in der zuvor durch path angegebenen Datei.

# utils.py
from rest_framework.views import exception_handler

def custom_exception_handler(exc, context):

    response = exception_handler(exc, context)
    if isinstance(exc, HogeError):
        content = {'detail': '{}'.format(exc.args)}
        return Response(content, status=status.HTTP_400_BAD_REQUEST)
    return response

Das Merkmal dieser Methode ist, dass die Fehler, die in allen Ansichten auftreten, in diesem custom_exception_handler zusammengefasst werden.

Jede dieser Methoden hat einen anderen Anwendungsbereich, daher möchte ich sie je nach Situation richtig anwenden.

Ich möchte den Wert von View an Serializer übergeben

Lösungen

Wenn Sie über die Lösung nachdenken, können Sie sie selbstverständlich einfach an den Serializer-Konstruktor (init) übergeben. In diesem Beispiel wird es an das Schlüsselwortargument user_data übergeben.

# views.py
class MyViewSet(views.ModelViewSet):
    def retrieve(self, request):
        user_data = request.GET['user_data']
        (...)
        serializer = MySerializer(My_list, many=True, user_data=user_data)

Auf der empfangenden Seite wird init überschrieben und vom Schlüsselwortargument empfangen.

# serializer.py
class MySerializer(serializers.ModelSerializer):
    class Meta:
        model = MyModel

    def __init__(self, *args, **kwargs):
        self.user_data = kwargs.pop('user_data', '')
        super(MySerializer, self).__init__(*args, **kwargs)

Ich glaube nicht, dass es üblich ist, View-Werte an Serializer zu übergeben, aber Sie können sie verwenden, wenn Sie Serializer verwenden.SerializersMethodFiels () usw.

das ist alles.

Referenz

Recommended Posts

Django REST Framework Ein wenig nützlich zu wissen.
Pythons itertools sind ein wenig nützlich zu wissen
Erstellen Sie eine REST-API, um dynamodb mit dem Django REST Framework zu betreiben
Grundlagen des Django REST-Frameworks
So erstellen Sie eine Rest-API in Django
Tipps zum Django Rest Framework
Erstellen Sie eine Todo-App mit Django REST Framework + Angular
Lassen Sie uns eine Todo-App mit dem Django REST-Framework erstellen
Wenn Sie mit dem Django REST-Framework filtern möchten
Django REST Framework Stolperstein
Django REST Framework mit Vue.js
Melden Sie sich mit dem Django Rest Framework an
So schreiben Sie eine benutzerdefinierte Validierung in Django REST Framework
Zurücksetzen des Passworts über die API mit dem Django Rest Framework
[Django] Verwenden Sie MessagePack mit dem Django REST-Framework
Erstellen Sie eine RESTful-API mit dem Django Rest Framework
Logisches Löschen in Django, DRF (Django REST Framework)
Verstehen Sie den Komfort des Django Rest Framework
Ein Verwaltungstool, das sofort mit dem REST-Framework ng-admin + Django erstellt werden kann
CRUD GET mit Nuxt & Django REST Framework ②
CRUD POST mit Nuxt & Django REST Framework
CRUD GET mit Nuxt & Django REST Framework ①
Überlegungen zum Design von Django REST Framework + Clean Architecture
Wie man mit verstümmelten Charakteren in json von Django REST Framework umgeht
Ich habe ein WebAPI gemacht! Erstellen einer Umgebung aus Django Rest Framework 1 mit EC2
Ich möchte eine API erstellen, die ein Modell mit einer rekursiven Beziehung im Django REST Framework zurückgibt
So können Sie die Funktionen des Django Rest Frameworks in einer Datei ausprobieren
Der Weg, um die Verbindung zwischen Nginx, Django und Uwsgi zu bekämpfen und ein wenig zu gewinnen
So generieren Sie automatisch ein API-Dokument mit dem Django REST-Framework und POST vom Dokumentbildschirm
Die Geschichte von Django, wie er eine Bibliothek erstellt, die vielleicht etwas nützlicher ist
CRUD PUT, DELETE mit Nuxt & Django REST Framework
So entwickeln Sie eine Cart-App mit Django
Implementieren Sie die JWT-Anmeldefunktion im Django REST-Framework
Ich würde gerne etwas über Django Page Nation erfahren
Für mich als Django-Anfänger (3) - Hallo Welt! --- ---.
Implementierung der Authentifizierungsfunktion in Django REST Framework mit djoser
Ich möchte eine Django-App auf Heroku hochladen
Manchmal möchten Sie mit DRF (Django REST Framework) auf View information from Serializer zugreifen.
Eine kleine Geschichte, die beim Schreiben von Twilio-Anwendungen mit Python auf AWS Lambda süchtig macht
Ein paar süchtig machende Informationen über Cliff, das CLI-Framework
Weitere neue Benutzerauthentifizierungsmethoden mit Django REST Framework
Python Ver. Einführung in WebPay mit ein wenig Code
(Python) Versuchen Sie, eine Webanwendung mit Django zu entwickeln
[CRUD] [Django] Erstellen Sie eine CRUD-Site mit dem Python-Framework Django ~ 1 ~
So stellen Sie eine Django-Anwendung in der Alibaba-Cloud bereit
Erstellen Sie eine API für die Benutzerauthentifizierung mit Django REST Framework
So erstellen Sie eine Django (Python) -Umgebung auf Docker
Schritte von der Installation von Python 3 bis zur Erstellung einer Django-App
[Django Rest Framework] Passen Sie die Filterfunktion mit Django-Filter an
[CRUD] [Django] Erstellen Sie eine CRUD-Site mit dem Python-Framework Django ~ 2 ~
Übergang zum Update-Bildschirm mit dem Django-Tag
Für mich als Django-Anfänger (1) -Erstellen eines Projekts / einer App-
So führen Sie Django unter IIS auf einem Windows-Server aus
So verweisen Sie auf statische Dateien in einem Django-Projekt
Für mich als Django-Anfänger (4) - Erstellen Sie eine Memo-App-
[CRUD] [Django] Erstellen Sie eine CRUD-Site mit dem Python-Framework Django ~ 3 ~
[CRUD] [Django] Erstellen Sie eine CRUD-Site mit dem Python-Framework Django ~ 4 ~
[CRUD] [Django] Erstellen Sie eine CRUD-Site mit dem Python-Framework Django ~ 5 ~
Für mich als Django-Anfänger (2) - Was ist MTV?