ViewSet e Router
I ViewSet e i Router sono strumenti di Django REST Framework che semplificano enormemente la creazione di API RESTful. Un ViewSet combina la logica di piuâ view correlate in unâunica classe, mentre un Router genera automaticamente la configurazione URL corrispondente.
ViewSet
Un ViewSet raggruppa le operazioni CRUD (Create, Read, Update, Delete) in una singola classe, eliminando la necessitaâ di scrivere view separate per ogni operazione.
from rest_framework import viewsets
from rest_framework.response import Response
from .models import Libro
from .serializers import LibroSerializer
class LibroViewSet(viewsets.ViewSet):
def list(self, request):
"""GET /libri/ - Lista tutti i libri"""
libri = Libro.objects.all()
serializer = LibroSerializer(libri, many=True)
return Response(serializer.data)
def create(self, request):
"""POST /libri/ - Crea un nuovo libro"""
serializer = LibroSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=201)
def retrieve(self, request, pk=None):
"""GET /libri/{id}/ - Dettaglio singolo libro"""
libro = Libro.objects.get(pk=pk)
serializer = LibroSerializer(libro)
return Response(serializer.data)
def update(self, request, pk=None):
"""PUT /libri/{id}/ - Aggiorna libro"""
libro = Libro.objects.get(pk=pk)
serializer = LibroSerializer(libro, data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
def destroy(self, request, pk=None):
"""DELETE /libri/{id}/ - Elimina libro"""
libro = Libro.objects.get(pk=pk)
libro.delete()
return Response(status=204)
ModelViewSet
ModelViewSet eâ la versione piuâ completa e automatizzata. Fornisce automaticamente tutte le operazioni CRUD semplicemente specificando il queryset e il serializer.
from rest_framework import viewsets
from .models import Libro, Autore
from .serializers import LibroSerializer, AutoreSerializer
class LibroViewSet(viewsets.ModelViewSet):
queryset = Libro.objects.all()
serializer_class = LibroSerializer
# Personalizza il queryset in base alla richiesta
def get_queryset(self):
queryset = Libro.objects.all()
autore = self.request.query_params.get('autore')
if autore:
queryset = queryset.filter(autore__nome__icontains=autore)
return queryset
# Esegui logica aggiuntiva al salvataggio
def perform_create(self, serializer):
serializer.save(aggiunto_da=self.request.user)
class AutoreViewSet(viewsets.ModelViewSet):
queryset = Autore.objects.all()
serializer_class = AutoreSerializer
ModelViewSet include automaticamente: list, create, retrieve, update, partial_update e destroy.
ReadOnlyModelViewSet
Quando si desidera esporre solo operazioni di lettura (GET), si puoâ utilizzare ReadOnlyModelViewSet, che fornisce solo list e retrieve.
class CategoriaViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Categoria.objects.all()
serializer_class = CategoriaSerializer
# Espone solo:
# GET /categorie/ -> lista
# GET /categorie/{id}/ -> dettaglio
Router
I Router generano automaticamente le URL per i ViewSet, eliminando la configurazione manuale.
DefaultRouter
DefaultRouter crea tutte le URL standard e aggiunge anche una pagina root che elenca tutti gli endpoint disponibili.
from rest_framework.routers import DefaultRouter
from .views import LibroViewSet, AutoreViewSet, CategoriaViewSet
router = DefaultRouter()
router.register(r'libri', LibroViewSet)
router.register(r'autori', AutoreViewSet)
router.register(r'categorie', CategoriaViewSet)
# URL generate automaticamente:
# /libri/ -> list, create
# /libri/{pk}/ -> retrieve, update, partial_update, destroy
# /autori/ -> list, create
# /autori/{pk}/ -> retrieve, update, partial_update, destroy
# /categorie/ -> list
# /categorie/{pk}/ -> retrieve
# / -> pagina root con lista endpoint
SimpleRouter
SimpleRouter funziona come DefaultRouter ma senza la pagina root dellâAPI.
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register(r'libri', LibroViewSet)
router.register(r'autori', AutoreViewSet)
Integrazione con le URL del Progetto
# urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from miaapp.views import LibroViewSet, AutoreViewSet
router = DefaultRouter()
router.register(r'libri', LibroViewSet)
router.register(r'autori', AutoreViewSet)
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include(router.urls)),
# Le URL dell'API saranno: /api/libri/, /api/autori/, ecc.
]
Azioni Personalizzate con @action
Il decoratore @action permette di aggiungere endpoint personalizzati a un ViewSet, al di laâ delle operazioni CRUD standard.
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
class LibroViewSet(viewsets.ModelViewSet):
queryset = Libro.objects.all()
serializer_class = LibroSerializer
# Azione sulla collezione: GET /libri/recenti/
@action(detail=False, methods=['get'])
def recenti(self, request):
libri_recenti = Libro.objects.order_by('-data_pubblicazione')[:10]
serializer = self.get_serializer(libri_recenti, many=True)
return Response(serializer.data)
# Azione su singola istanza: POST /libri/{id}/pubblica/
@action(detail=True, methods=['post'])
def pubblica(self, request, pk=None):
libro = self.get_object()
libro.pubblicato = True
libro.save()
return Response({'stato': 'Libro pubblicato'})
# Azione con URL personalizzata
@action(detail=True, methods=['get'], url_path='statistiche-vendita')
def statistiche_vendita(self, request, pk=None):
libro = self.get_object()
stats = {
'copie_vendute': libro.copie_vendute,
'ricavo_totale': libro.copie_vendute * libro.prezzo,
}
return Response(stats)
Il parametro detail=True indica che lâazione opera su una singola istanza (richiede un pk), mentre detail=False opera sullâintera collezione.
Conclusione
I ViewSet e i Router di Django REST Framework offrono un modo elegante e conciso per costruire API RESTful complete. ModelViewSet riduce drasticamente il codice necessario per le operazioni CRUD, mentre i Router automatizzano la configurazione delle URL. Il decoratore @action aggiunge flessibilitaâ per endpoint personalizzati, rendendo possibile gestire qualsiasi logica di business allâinterno di unâarchitettura pulita e organizzata.