logo cosasdedevs

Creación, lectura, actualización y borrado con Django Rest Framework

Creación, lectura, actualización y borrado con Django Rest Framework

My Profile
Jun 26, 2020

¡Hey! Bienvenidos a la tercera parte de este tutorial para aprender a crear una API con Django Rest Framework. En el tutorial de hoy nos vamos a enfocar en la creación, listado, actualización y borrado de los distintos apartados de un curriculum de usuario y vais a flipar viendo como nos facilita el trabajo este framework 😯.

Pero antes de nada lo primero que debemos hacer es ir al archivo settings.py y añadir una configuración extra para Django Rest Framework.

api_drf_curriculum/settings.py

# Django REST Framework
REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
    ),
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
    'PAGE_SIZE': 10,
}

En DEFAULT_RENDERER_CLASSES definimos el tipo de respuesta que daremos al usuario, nosotros devolveremos un Json y se pueden añadir más tipos al listado.

Con DEFAULT_AUTHENTICATION_CLASSES definimos el tipo de autenticación, como vimos en el tutorial anterior, nosotros utilizaremos la autenticación por Token.

Por último seleccionaremos el paginador y el número máximo de resultados por página que en nuestro caso será de 10.

Para ver más información acerca de la configuración pinchad aquí.

Ahora vamos a ponernos manos a la obra con la creación y empezaremos con la experiencia, para ello lo primero que haremos será crear un serializer para esta app.

experiences/serializers.py


# Django REST Framework
from rest_framework import serializers
# Model
from experiences.models import Experience

class ExperienceModelSerializer(serializers.ModelSerializer):
    """Experience Model Serializer"""

    class Meta:
        """Meta class."""

        model = Experience
        fields = (
            'pk',
            'date_ini',
            'date_end',
            'company',
            'description',
        )

class ExperienceSerializer(serializers.Serializer):

    user = serializers.HiddenField(default=serializers.CurrentUserDefault())
    date_ini = serializers.DateTimeField()
    date_end = serializers.DateTimeField(required=False)
    company = serializers.CharField(max_length=250)
    description = serializers.CharField(max_length=10000)

    def create(self, data):

        exp = Experience.objects.create(**data)
        return exp


Es bastante similar al que definimos para el usuario, declaramos un model serializer para recuperar los datos y creamos otro serializer que se encargará de la validación de los datos y de la creación de la fila en la tabla. Como podéis observar, hemos añadido un campo user donde asignamos el usuario autenticado como el usuario que estará asignado a la experiencia que vamos a añadir.

Antes de seguir con las vistas, vamos a ver otra funcionalidad que provee Django Rest Framework que son los permisos. Estos nos permiten limitar a que puede acceder el usuario según su configuración. Podemos usar los predefinidos por el framework y customizar nuestros propios permisos y, ya que solo los usuarios que no son reclutadores pueden crear los datos como experiencia, vamos a crear un permiso. Para ello en nuestra app users creamos un archivo llamado permissions.py.

users/permissions.py

"""User permission classes."""

# Django REST Framework
from rest_framework.permissions import BasePermission

# Models
from users.models import User


class IsStandardUser(BasePermission):
    """Allow access to create experience, extras and proyects."""

    def has_permission(self, request, view):

        try:
            user = User.objects.get(
                email=request.user,
                is_recruiter=False
            )
        except User.DoesNotExist:
            return False
        return True

Aquí básicamente lo que hacemos es extender de la clase BasePermision y validamos si el usuario autenticado es reclutador o no, según el resultado devolvemos True o False. Es importante recalcar que solo son válidas estas dos respuestas así que si devolvéis otra cosa enviará un error. Os dejo la documentación sobre los permisos por si queréis profundizar en este tema.

Ahora que ya tenemos los permisos es hora de crear la vista, para ello abrimos el archivo views.py de la app experiences.

experiences/views.py


# Django REST Framework
from rest_framework import mixins, status, viewsets
from rest_framework.response import Response

# Permissions
from rest_framework.permissions import IsAuthenticated
from users.permissions import IsStandardUser

#Serializers
from experiences.serializers import (ExperienceModelSerializer, ExperienceSerializer)

class ExperienceViewSet(mixins.CreateModelMixin,
                        viewsets.GenericViewSet):

    serializer_class = ExperienceModelSerializer

    def get_permissions(self):
        permission_classes = [IsAuthenticated, IsStandardUser]
        return [permission() for permission in permission_classes]

        
    def create(self, request, *args, **kwargs):
        serializer = ExperienceSerializer(data=request.data, context={"request": self.request})
        serializer.is_valid(raise_exception=True)
        exp = serializer.save()
        data = ExperienceModelSerializer(exp).data
        return Response(data, status=status.HTTP_201_CREATED)
        

Es bastante similar a la vista para crear usuarios pero aquí hemos añadido algunas cosas nuevas que os voy explicar.

Lo primero que podréis observar es que estamos importando una nueva librería llamada mixins. Las clases mixin proporcionan las acciones que se utilizan para obtener el comportamiento de vista básico. Eso quiere decir que nos facilitará mucho el trabajo a la hora de la creación, listado, actualización y borrado en nuestra API.

Después estamos importando el permiso IsAuthenticated que lo que hará será comprobar si estamos autenticados y el permiso que creamos anteriormente para comprobar si es un usuario estándar o un reclutador.

Después creamos la vista ExperienceViewSet que además de extender de GenericViewSet también lo hará de CreateModelMixin lo que ya nos proporcionará toda la configuración para la creación, eso quiere decir que no tenemos que crear una url en específico para la creación de la experiencia y tampoco decirle que los datos deben ser enviados por el método POST, el mixin ya se encarga de ello.

Aquí vemos el uso de un método nuevo que es get_permissions, en él le decimos que permisos debe cumplir para poder usar esta vista.

Por último usamos el método create para realizar la creación de la experiencia del usuario.

Ahora que ya tenemos la vista solo necesitamos añadir las urls como hicimos con los usuarios y listo.

experiences/urls.py

"""Experience URLs."""

# Django
from django.urls import include, path

# Django REST Framework
from rest_framework.routers import DefaultRouter

# Views
from experiences import views

router = DefaultRouter()
router.register(r'experience', views.ExperienceViewSet, basename='experience')

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

api_drf_curriculum/urls.py

"""Main URLs module."""

from django.conf import settings
from django.urls import include, path
from django.conf.urls.static import static
from django.contrib import admin

urlpatterns = [
    # Django Admin
    path('admin/', admin.site.urls),

    path('', include(('users.urls', 'users'), namespace='users')),
    path('', include(('experiences.urls', 'experience'), namespace='experience')),

] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Una vez tenemos todo listo es hora de realizar una prueba, recordad que tenéis para crear la experiencia deberéis pasar la autenticación como cabecera para que todo funcione. Os dejo el ejemplo de como lo he hecho con Postman.

Listado de experiencia del usuario

Ahora vais a ver lo fácil que es generar el listado de experiencia por usuario, para ello vamos al archivo views de la app experiencies.

experiences/views.py

Lo primero que necesitamos hacer importar el modelo Experience para usarlo más adelante.

# Models
from experiences.models import Experience

Después añadimos un nuevo mixin llamado ListModelMixin que se encargará de toda la petición, generar el listado y limitarlo según el número máximo de respuesta que hayamos añadido.

class ExperienceViewSet(mixins.ListModelMixin,
                        mixins.CreateModelMixin,
                        viewsets.GenericViewSet):

Por último, dentro de ExperienceViewSet añadimos el get_queryset en el que filtraremos por el usuario autenticado y ya lo tenemos 💪.

    def get_queryset(self):
        """Restrict list to only user experience."""
        queryset = Experience.objects.filter(user=self.request.user)
        return queryset

Ahora solo falta probarlo, para ello vamos a Postman, hacemos una petición get a http://localhost:8000/experience/ sin olvidar pasar nuestro token por la cabecera y ya deberíamos ver el listado.

Ahora nos vamos a encargar de realizar las mismas acciones para las apps education, extras y projects, ya que no implica nada nuevo, simplemente añadiré el código.

Education

education/serializers.py


# Django REST Framework
from rest_framework import serializers
# Model
from education.models import Education

class EducationModelSerializer(serializers.ModelSerializer):
    """Education Model Serializer"""

    class Meta:
        """Meta class."""

        model = Education
        fields = (
            'pk',
            'date_ini',
            'date_end',
            'title',
        )

class EducationSerializer(serializers.Serializer):

    user = serializers.HiddenField(default=serializers.CurrentUserDefault())
    date_ini = serializers.DateTimeField()
    date_end = serializers.DateTimeField(required=False)
    title = serializers.CharField(max_length=255)

    def create(self, data):

        education = Education.objects.create(**data)
        return education

education/views.py


# Django REST Framework
from rest_framework import mixins, status, viewsets
from rest_framework.response import Response

# Permissions
from rest_framework.permissions import IsAuthenticated
from users.permissions import IsStandardUser

# Serializers
from education.serializers import (EducationModelSerializer, EducationSerializer)

# Models
from education.models import Education

class EducationViewSet(mixins.ListModelMixin,
                        mixins.CreateModelMixin,
                        viewsets.GenericViewSet):

    serializer_class = EducationModelSerializer

    def get_permissions(self):
        permission_classes = [IsAuthenticated, IsStandardUser]
        return [permission() for permission in permission_classes]


    def get_queryset(self):
        """Restrict list to only user Education."""
        queryset = Education.objects.filter(user=self.request.user)
        return queryset

        
    def create(self, request, *args, **kwargs):
        serializer = EducationSerializer(data=request.data, context={"request": self.request})
        serializer.is_valid(raise_exception=True)
        exp = serializer.save()
        data = EducationModelSerializer(exp).data
        return Response(data, status=status.HTTP_201_CREATED)

education/urls.py

"""Education URLs."""

# Django
from django.urls import include, path

# Django REST Framework
from rest_framework.routers import DefaultRouter

# Views
from education import views

router = DefaultRouter()
router.register(r'education', views.EducationViewSet, basename='education')

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

Projects

projects/serializers.py


# Django REST Framework
from rest_framework import serializers
# Model
from projects.models import Project

class ProjectModelSerializer(serializers.ModelSerializer):
    """Projects Model Serializer"""

    class Meta:
        """Meta class."""

        model = Project
        fields = (
            'pk',
            'date',
            'title',
            'url',
            'description',
        )

class ProjectSerializer(serializers.Serializer):

    user = serializers.HiddenField(default=serializers.CurrentUserDefault())
    date = serializers.DateTimeField()
    title = serializers.CharField(max_length=255)
    url = serializers.URLField(required=False)
    description = serializers.CharField(max_length=5000)

    def create(self, data):

        pro = Project.objects.create(**data)
        return pro

projects/views.py


# Django REST Framework
from rest_framework import mixins, status, viewsets
from rest_framework.response import Response

# Permissions
from rest_framework.permissions import IsAuthenticated
from users.permissions import IsStandardUser

# Serializers
from projects.serializers import (ProjectModelSerializer, ProjectSerializer)

# Models
from projects.models import Project

class ProjectViewSet(mixins.ListModelMixin,
                        mixins.CreateModelMixin,
                        viewsets.GenericViewSet):

    serializer_class = ProjectModelSerializer

    def get_permissions(self):
        permission_classes = [IsAuthenticated, IsStandardUser]
        return [permission() for permission in permission_classes]


    def get_queryset(self):
        """Restrict list to only user Project."""
        queryset = Project.objects.filter(user=self.request.user)
        return queryset

        
    def create(self, request, *args, **kwargs):
        serializer = ProjectSerializer(data=request.data, context={"request": self.request})
        serializer.is_valid(raise_exception=True)
        exp = serializer.save()
        data = ProjectModelSerializer(exp).data
        return Response(data, status=status.HTTP_201_CREATED)

projects/urls.py

"""Projects URLs."""

# Django
from django.urls import include, path

# Django REST Framework
from rest_framework.routers import DefaultRouter

# Views
from projects import views

router = DefaultRouter()
router.register(r'projects', views.ProjectViewSet, basename='projects')

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

Extras

extras/serializers.py


# Django REST Framework
from rest_framework import serializers
# Model
from extras.models import Extra

class ExtraModelSerializer(serializers.ModelSerializer):
    """Extras Model Serializer"""

    class Meta:
        """Meta class."""

        model = Extra
        fields = (
            'pk',
            'expedition',
            'title',
            'url',
            'description',
        )

class ExtraSerializer(serializers.Serializer):

    user = serializers.HiddenField(default=serializers.CurrentUserDefault())
    expedition = serializers.DateTimeField()
    title = serializers.CharField(max_length=255)
    url = serializers.URLField(required=False)
    description = serializers.CharField(max_length=5000)

    def create(self, data):

        extra = Extra.objects.create(**data)
        return extra

extras/views.py


# Django REST Framework
from rest_framework import mixins, status, viewsets
from rest_framework.response import Response

# Permissions
from rest_framework.permissions import IsAuthenticated
from users.permissions import IsStandardUser

# Serializers
from extras.serializers import (ExtraModelSerializer, ExtraSerializer)

# Models
from extras.models import Extra

class ExtraViewSet(mixins.ListModelMixin,
                        mixins.CreateModelMixin,
                        viewsets.GenericViewSet):

    serializer_class = ExtraModelSerializer

    def get_permissions(self):
        permission_classes = [IsAuthenticated, IsStandardUser]
        return [permission() for permission in permission_classes]


    def get_queryset(self):
        """Restrict list to only user Extra formation."""
        queryset = Extra.objects.filter(user=self.request.user)
        return queryset

        
    def create(self, request, *args, **kwargs):
        serializer = ExtraSerializer(data=request.data, context={"request": self.request})
        serializer.is_valid(raise_exception=True)
        exp = serializer.save()
        data = ExtraModelSerializer(exp).data
        return Response(data, status=status.HTTP_201_CREATED)

extras/urls.py

"""Extras URLs."""

# Django
from django.urls import include, path

# Django REST Framework
from rest_framework.routers import DefaultRouter

# Views
from extras import views

router = DefaultRouter()
router.register(r'extras', views.ExtraViewSet, basename='extras')

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

Por último solo falta añadir las urls en el archivo api_drf_curriculum/urls.py.

api_drf_curriculum/urls.py

"""Main URLs module."""

from django.conf import settings
from django.urls import include, path
from django.conf.urls.static import static
from django.contrib import admin

urlpatterns = [
    # Django Admin
    path('admin/', admin.site.urls),

    path('', include(('users.urls', 'users'), namespace='users')),
    path('', include(('experiences.urls', 'experience'), namespace='experience')),
    path('', include(('education.urls', 'education'), namespace='education')),
    path('', include(('projects.urls', 'projects'), namespace='projects')),
    path('', include(('extras.urls', 'extras'), namespace='extras')),

] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Actualización y borrado

Para utilizar la actualización y borrado solo debemos añadir dos nuevos mixins que son UpdateModelMixin y DestroyModelMixin que se encargarán de la actualización y borrado del objeto seleccionado.

experiences/views.py

class ExperienceViewSet(mixins.ListModelMixin,
                        mixins.CreateModelMixin,
                        mixins.UpdateModelMixin,
                        mixins.DestroyModelMixin,
                        viewsets.GenericViewSet):

Una vez añadidos solo tenemos que llamar a la url pasando la primary key en ella y método que sería PUT para actualizaciones completas, PATCH para actualizaciones parciales y DELETE para eliminar el objeto.

Y listo, ya esta, no hay que hacer nada más. Esta es la magia de DRF, si quisierais añadir configuración extra podríais sobreescribir los métodos que contienen estos mixins para adaptarlos a vuestras necesidades.

Ahora solo faltaría añadirlos a las vistas de education, experiencie y extras y ya lo podríamos usar en toda nuestra API.

Una vez añadidos ya podemos decir por fin tenemos configurada nuestra api para crear, listar, actualizar y borrar la información del usuario 💪.

La próxima semana seguiremos con este tutorial en el que nos encargaremos de crear un buscador para los reclutadores. Como siempre avisaré por mi Twitter cuando esté listo así que si queréis estar al tanto de cuando sale el nuevo tutorial no olvidéis seguirme. También os agradecería que compartieseis este tutorial si os ayudado o si creéis que puede ayudar a otras personas.

Nos leemos 👋

363 vistas

Nos tomamos en serio tu privacidad

Utilizamos cookies propias y de terceros para mejorar la experiencia del usuario a través de su navegación. Si pulsas entendido aceptas su uso. Ver política de cookies.

🐍 Sígueme en Twitter

Si te gusta el contenido que subo y no quieres perderte nada, sígueme en Twitter y te avisaré cada vez que cree contenido nuevo 💪
Luego ¡Te sigo!