Django REST Framework

Ernesto Rico Schmidt am 20. September 2019

Eine elegante REST-Schnittelle für Django-Applikationen

Wenn es darum geht für eine Django-Applikation eine REST-Schnittelle zu entwickeln, dann gibt es eine Reihe von Möglichkeiten.

API Creation

Django REST Framework hat sich zum de-facto-Standard entwickelt. Es bietet Authentifizierung, auch mit OAuth1a und OAuth2, Serialisierung von ORM- und nicht-ORM-Daten, Funktions-basierte und generische Views und das mit einer ausführlichen Dokumentation und eine navigierbare Schnittstelle.

Schnittstelle für PISLEA

Für die bereits vorhandene Django-Applikation hinter PISLEA die öffentlichen Ausschreibungen Boliviens verfolgt, möchten wir eine sehr einfache Schnittstelle anbieten, um vorhandene Ausschreibungen aufzulisten, die entweder als kontaminiert oder exemplarisch sind.

Installation

Wir klonen das Git-Repository und installieren die Django-Applikation in einer virtuellen Umgebung:

$ git clone https://github.com/nnrcschmdt/pislea2.git
$ cd seguimiento
$ python3 -m venv venv
$ source venv/bin/activate
(venv) $ pip install -r requirements/base.txt

Konfiguration

Wir aktivieren die rest_framework Applikation, und definieren die Klasse für die Seitennummerierung und die Größe der Seiten:

# seguimiento/settings/base.py

INSTALLED_APPS = [
    'rest_framework'
]

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
    'PAGE_SIZE': 100
}

Serializers

Der erste Schritt ist eine Serializer-Klasse zu definieren. In diesem Fall leiten wir die Klasse von serializers.HyperlinkedModelSerializer ab. So wird die Antwort navigierbar sein, und einen Link auf die Seite der Ausschreibung in url enthalten. Wir verlinken mit model = Convocatoria das Modell und listen mit fields die Felder des Models auf, die in der Antwort enthalten sein werden.

Hätten wir mehr als ein Modell, und Referenzen auf diese, dann wären sie einfach miteinander verlinkt.

# convocatorias/serializers.py

from rest_framework import serializers

from .models import Convocatoria

class ConvocatoriaSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        extra_kwargs = {
            'url': {'lookup_field': 'slug'}
        }
        fields = ['url', 'entidad', 'departamento', 'slug', 'objeto', 'modalidad', 'tipo', 'estatus', 'notas']
        model = Convocatoria

Viewset

Der nächste Schritt ist die Definition von einem Viewset. Diese repräsentiert die Daten bzw. eine Sicht auf diese. Die Klasse wird vom ReadOnlyModelViewSet abgeleitet und so nur das Lesen von Daten erlauben. Wir legen zusätzlich fest, dass nur die Ausschreibungen mit dem Status 7 (kontaminiert) und 8 (exemplarisch) aufgelistet werden.

Wir definieren zuletzt die Möglichkeit die Ausschreibungen nach Einheit (entidad), Status (estatus) und Departement (departamento) zu filtern. Diese können als Parameter in der URL mit angegeben werden.

# convocatorias/views.py

from rest_framework import viewsets
from .serializers import ConvocatoriaSerializer

class ConvocatoriaViewset(viewsets.ReadOnlyModelViewSet):
    queryset = Convocatoria.objects.filter(estatus__in=[7, 8])
    serializer_class = ConvocatoriaSerializer

    def get_queryset(self):
        queryset = Convocatoria.objects.filter(estatus__in=[7, 8])

        entidad = self.request.query_params.get('entidad', None)
        estatus = self.request.query_params.get('estatus', None)
        departamento = self.request.query_params.get('departamento', None)

        if entidad:
            queryset = queryset.filter(entidad=entidad)
        if estatus:
            queryset = queryset.filter(estatus=estatus)
        if departamento:
            queryset = queryset.filter(departamento=departamento)

        return queryset

URLs und Router

Der letzte Schritt ist die Konfiguration der URLs. Wir verwenden dafür den Router und registrieren den Pfad convocatorias mit dem ConvocatoriaViewset.

# seguimiento/urls.py

from rest_framework.routers import DefaultRouter
from convocatorias.views import ConvocatoriaViewset

router = DefaultRouter()
router.register('convocatorias', ConvocatoriaViewset)

API_TITLE = 'Convocatorias PISLEA API'
API_DESCRIPTION = 'API para consultar las convocatorias contaminadas y ejemplares'

urlpatterns = [
    path('api/', include(router.urls))
]

Schnittstelle

Das Ergebnis ist eine navigierbare Schnittelle, die die möglichen Pfade auflistet:

API Root

Die Schnittelle liefert 100 Ausschreibungen pro Seite. Diese können entweder als navigierbare Schnittstelle dargestellt werden:

Navigierbare Scnittstelle

Oder einfach die JSON-Kodierte Daten geliefert werden.

JSON-Antowrt

Das Django-Projekt seguimiento ist auf GitHub zu finden.