Relaciones anidadas en serializadores para campos OneToOne en Django Rest Framework

Django Rest Framework (DRF) es uno de los frameworks escritos de manera efectiva alrededor de Django y ayuda a construir API REST para el back-end de una aplicación.

Lo estaba usando en uno de mis proyectos personales y me topé con el desafío de "serializar un modelo que hace referencia a otro modelo a través del campo OneToOne".

`Estaba usando el modelo de usuario de django.contrib.auth.models. Quería escribir una API para crear y actualizar un objeto de usuario a través de una única API que también actualiza los atributos de mi modelo. La solución fue utilizar las relaciones anidadas de DRF en la serialización.

Asumiré que tiene un conocimiento práctico razonable de Python, virtualenv, pip, Django y DRF antes de continuar. De lo contrario, obtenga más información y no dude en volver si alguna vez se queda atascado en relaciones anidadas en la serialización.

El ejemplo que estoy considerando aquí es un modelo de estudiante universitario , que hace referencia al modelo de usuario a través del campo OneToOne. Mi objetivo es una API única para crear y obtener detalles de usuario como nombre, nombre de usuario y correo electrónico junto con un atributo de estudiante como la asignatura principal.

Así es como se models.pyve mi :

from django.db import models from django.contrib.auth.models import User class UnivStudent(models.Model): """ A class based model for storing the records of a university student Note: A OneToOne relation is established for each student with User model. """ user = models.OneToOneField(User) subject_major = models.CharField(name="subject_major", max_length=60)

A continuación, el serializador del modelo anterior determina los atributos a manipular. Si observa a continuación, tengo 2 clases de serializador,UserSerializery StudentSerializer.Este es nuestro punto de interés.

He declarado un useratributo que es un campo de serializador aquí. Ese useratributo contendrá principalmente la referencia completa de la UserSerializerclase. En los campos de StudentSerializer, solo vemos user"y subject_major". Esto nos permite ingresar los atributos de estudiante (o usuario) junto con subject_major.

Se crea una entrada de usuario a la que hace referencia la entrada de estudiante. Anulamos el método de creación de StudentSerializerpara crear un userobjeto primero y lo usamos para crear el studentobjeto.

El serializer.py es el siguiente:

from rest_framework import serializers, status from models import * class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ('username', 'first_name', 'last_name', 'email') class StudentSerializer(serializers.ModelSerializer): """ A student serializer to return the student details """ user = UserSerializer(required=True) class Meta: model = UnivStudent fields = ('user', 'subject_major',) def create(self, validated_data): """ Overriding the default create method of the Model serializer. :param validated_data: data containing all the details of student :return: returns a successfully created student record """ user_data = validated_data.pop('user') user = UserSerializer.create(UserSerializer(), validated_data=user_data) student, created = UnivStudent.objects.update_or_create(user=user, subject_major=validated_data.pop('subject_major')) return student

El views.pydebe ser muy sencillo si ya está familiarizado con las opiniones basadas en la clase de Django. Usaremos el serializador para validar y crear los objetos del modelo:

from serializers import * from models import * from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status class StudentRecordView(APIView): """ A class based view for creating and fetching student records """ def get(self, format=None): """ Get all the student records :param format: Format of the student records to return to :return: Returns a list of student records """ students = UnivStudent.objects.all() serializer = StudentSerializer(students, many=True) return Response(serializer.data) def post(self, request): """ Create a student record :param format: Format of the student records to return to :param request: Request object for creating student :return: Returns a student record """ serializer = StudentSerializer(data=request.data) if serializer.is_valid(raise_exception=ValueError): serializer.create(validated_data=request.data) return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.error_messages, status=status.HTTP_400_BAD_REQUEST)

He incluido /univstud/url por logro posty getsolicitudes para estudiante universitario.

from django.conf.urls import patterns, include, url from django.contrib import admin from rest_framework import routers from rest_framework.urlpatterns import format_suffix_patterns from OneToOne import views admin.autodiscover() router = routers.DefaultRouter() urlpatterns = patterns('', url(r'^admin/', include(admin.site.urls)), url(r'^api-auth/', include('rest_framework.urls', namespace="rest_framework")), ) urlpatterns += format_suffix_patterns([ # API to map the student record url(r'^api/univstud/$', views.StudentRecordView.as_view(), name="students_list"), ])

La POSTllamada de solicitud se vería así:

La Getllamada de solicitud se vería así:

¡Eso es todo!:)

Por tanto, la relación anidada está habilitada para StudentSerializerhacer referencia user.

El código completo está en mi repositorio de gitlab.

Referencias:

  1. //www.django-rest-framework.org/api-guide/relations/