Skip to content

Vistas basadas en clases

Modelo Cliente

También podemos escribir nuestras vistas de API utilizando vistas basadas en clases, en lugar de vistas basadas en funciones. Como veremos, este es un patrón poderoso que nos permite reutilizar la funcionalidad común y nos ayuda a mantener nuestro código Limpio.

Uso de vistas genéricas basadas en clases

En el archivo Apps/clientes/views.py colocamos el código correspondiente para realizar el CRUD completo.

from django.shortcuts import render
from django.http import Http404

from rest_framework.response import Response
from rest_framework import generics

from rest_framework import status

from Apps.clientes.models import Cliente
from Apps.clientes.serializers import ClienteSerializer

# Create your views here.


class ClienteList(generics.ListCreateAPIView):
    """
    Lista de Clientes
    """

    queryset = Cliente.objects.all()
    serializer_class = ClienteSerializer



class ClienteDetail(generics.RetrieveUpdateDestroyAPIView):
    """
    Retrieve, update or delete de los clientes por pk
    """
    queryset = Cliente.objects.all()
    serializer_class = ClienteSerializer

Código en el archivo Apps/clientes/serializers.py

from dataclasses import field
from statistics import mode

from rest_framework import serializers
from Apps.clientes.models import Cliente

class ClienteSerializer(serializers.ModelSerializer):
    # len_nombreCliente = serializers.SerializerMethodField()
    class Meta:
        model = Cliente
        fields = "__all__"
        # exclude = ['passwordCliente']
        # fields = (
        #     'pk',
        #     'nombreCliente',
        #     'direccionCliente',
        #     'telefonoCliente',
        #     'correoCliente',
        #     'passwordCliente',
        # )

    # def get_len_nombreCliente(self, object):
    #     length = len(object.nombreCliente)
    #     return length

    # def validate(self, data):
    #     if data['nombreCliente'] == data['direccionCliente']:
    #         raise serializers.ValidationError('Nombre y Correo No pueden ser iguales')
    #     else:
    #         return data

    def validate_nombreCliente(self, value):
        if len(value) < 3:
            raise serializers.ValidationError('Nombre no puede ser tan corto')
        else:
            return value

    def validate_passwordCliente(self, value):
        if len(value) < 8:
            raise serializers.ValidationError('El Password debe tener mayor de 8 caracteres')
        else:
            return value

Código en el archivo Apps/clientes/urls.py

from django.urls import path
from Apps.clientes.views import ClienteList, ClienteDetail

app_name = "clientes"
urlpatterns = [
    path('', ClienteList.as_view()),
    path('<int:pk>', ClienteDetail.as_view()),

Uso de Mezclas de clases

Una de las grandes ventajas de usar vistas basadas en clases es que nos permite componer fácilmente fragmentos de comportamiento reutilizables.

Las operaciones de creación/recuperación/actualización/eliminación que hemos estado usando hasta ahora serán bastante similares para cualquier vista de API respaldada por modelo que creemos. Esos bits de comportamiento común se implementan en las clases mixtas del marco REST.

Echemos un vistazo a cómo podemos componer las vistas usando las clases mixin. Aquí está nuestro Apps/clientes/views.py

from django.shortcuts import render
from django.http import Http404

from rest_framework.response import Response
from rest_framework import generics
from rest_framework import mixins

from rest_framework import status

from Apps.clientes.models import Cliente
from Apps.clientes.serializers import ClienteSerializer

# Create your views here.


class ClienteList(mixins.ListModelMixin,
                  mixins.CreateModelMixin,
                  generics.GenericAPIView):
    """
    Lista de Clientes
    """

    queryset = Cliente.objects.all()
    serializer_class = ClienteSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)



class ClienteDetail(mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    generics.GenericAPIView):
    """
    Retrieve, update or delete de los clientes por pk
    """
    queryset = Cliente.objects.all()
    serializer_class = ClienteSerializer

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

Los archivos:

Apps/clientes/serializers.py

Apps/clientes/urls.py

Quedan exactamente igual al método anterior.

Reescribiendo nuestra API usando vistas basadas en clases

En el archivo Apps/clientes/views.py colocamos el código correspondiente para realizar el CRUD completo.

from django.shortcuts import render
from django.http import Http404
from django.http import JsonResponse

from rest_framework.response import Response
from rest_framework.views import APIView

from rest_framework import status

from Apps.clientes.models import Cliente
from Apps.clientes.serializers import ClienteSerializer, ClienteListSerializer

# Create your views here.


class ClienteList(APIView):
    """
    Lista de Clientes
    """

    def get(self, request, format=None):
        clientes = Cliente.objects.all()
        # data = {"results": list(clientes.values("nombreCliente", "direccionCliente", "telefonoCliente", "correoCliente", "passwordCliente"))}
        # print(data)
        # return JsonResponse(data)
        serializer = ClienteListSerializer(clientes, many=True)
        return Response({"clientes":serializer.data})

    def post(self, request, format=None):
        serializer = ClienteSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data,
                            status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class ClienteDetail(APIView):
    """
    Retrieve, update or delete de los clientes por pk
    """
    def get_object(self, pk):
        # Returns an object instance that should 
        # be used for detail views.
        try:
            return Cliente.objects.get(pk=pk)
        except Cliente.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        cliente = self.get_object(pk)
        serializer = ClienteListSerializer(cliente)
        return Response({"cliente":serializer.data})

    def put(self, request, pk, format=None):
        cliente = self.get_object(pk)
        serializer = ClienteSerializer(cliente, data=request.data)  
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def patch(self, request, pk, format=None):
        cliente = self.get_object(pk)
        serializer = ClienteSerializer(cliente,
                                           data=request.data,
                                           partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


    def delete(self, request, pk, format=None):
        cliente = self.get_object(pk)
        cliente.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

Los archivos:

Apps/clientes/serializers.py

Apps/clientes/urls.py

Quedan exactamente igual al método anterior.

Ahora probamos con http://localhost:8000/clientes/

También podemos probar el método Post,

Donde se muestra luego el resultado, con el método Get.

Ahora probamos el Método Put.

Se obtiene como resultado

Y por ultimo probamos el Metodo Delete

Validaciones de los Atributos

Las validaciones de cada uno de los atributos se hacen en Apps/clientes/serializers.py

from dataclasses import field
from statistics import mode

from rest_framework import serializers
from Apps.clientes.models import Cliente

class ClienteSerializer(serializers.ModelSerializer):
    class Meta:
        model = Cliente
        # fields = "__all__"
        exclude = ['passwordCliente']
        # fields = (
        #     'pk',
        #     'nombreCliente',
        #     'direccionCliente',
        #     'telefonoCliente',
        #     'correoCliente',
        #     'passwordCliente',
        # )
    def validate(self, data):
        if data['nombreCliente'] == data['direccionCliente']:
            raise serializers.ValidationError('Nombre y Correo No pueden ser iguales')
        else:
            return data

    def validate_nombreCliente(self, value):
        if len(value) < 3:
            raise serializers.ValidationError('Nombre no puede ser tan corto')
        else:
            return value

Personalizacion de los Atributos

Las personalizaciones de nuevos atributos se hacen en Apps/clientes/serializers.py

from dataclasses import field
from statistics import mode

from rest_framework import serializers
from Apps.clientes.models import Cliente

class ClienteSerializer(serializers.ModelSerializer):
    len_nombreCliente = serializers.SerializerMethodField()
    class Meta:
        model = Cliente
        # fields = "__all__"
        exclude = ['passwordCliente']
        # fields = (
        #     'pk',
        #     'nombreCliente',
        #     'direccionCliente',
        #     'telefonoCliente',
        #     'correoCliente',
        #     'passwordCliente',
        # )

    def get_len_nombreCliente(self, object):
        length = len(object.nombreCliente)
        return length

    def validate(self, data):
        if data['nombreCliente'] == data['direccionCliente']:
            raise serializers.ValidationError('Nombre y Correo No pueden ser iguales')
        else:
            return data

    def validate_nombreCliente(self, value):
        if len(value) < 3:
            raise serializers.ValidationError('Nombre no puede ser tan corto')
        else:
            return value

Envolviendo Vistas en API - Con @apiview

En el archivo Apps/clientes/views.py colocamos el código correspondiente para realizar el CRUD completo.

from django.shortcuts import render
from django.http import Http404

from rest_framework.response import Response
from rest_framework.decorators import api_view

from rest_framework import status

from Apps.clientes.models import Cliente
from Apps.clientes.serializers import ClienteSerializer

# Create your views here.


@api_view(['GET', 'POST'])
def cliente_list(request):
    """
    List all code snippets, or create a new snippet.
    """
    if request.method == 'GET':
        clientes = Cliente.objects.all()
        serializer = ClienteSerializer(clientes, many=True)
        return Response(serializer.data)

    elif request.method == 'POST':
        serializer = ClienteSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


@api_view(['GET', 'PUT', 'DELETE'])
def cliente_detail(request, pk):
    """
    Retrieve, update or delete a code snippet.
    """
    try:
        cliente = Cliente.objects.get(pk=pk)
    except Cliente.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)

    if request.method == 'GET':
        serializer = ClienteSerializer(cliente)
        return Response(serializer.data)

    elif request.method == 'PUT':
        serializer = ClienteSerializer(cliente, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    elif request.method == 'DELETE':
        cliente.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

Código en el archivo Apps/clientes/urls.py

"""
Envolviendo Vistas de Api
"""

from django.urls import path
from Apps.clientes.views import cliente_list, cliente_detail

urlpatterns = [
    path('', cliente_list),
    path('<int:pk>/', cliente_detail),
]

El archivo:

Apps/clientes/serializers.py

Quedan exactamente igual al método anterior.