00
:
00
:
00
:
00
•Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

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.