sirve - django rest frameworks
¿Cómo escribir un serializador/campo django-rest-framework para fusionar datos de relaciones genéricas? (1)
Tengo objetos con una relación genérica que apunta a varios otros objetos, y necesito que se fusionen (en línea) para que los objetos serializados parezcan un objeto completo.
P.EJ:
class Enrollement(models.Model):
hq = models.ForeignKey(Hq)
enrollement_date = models.Datetime()
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
object = generic.GenericForeignKey(''content_type'', ''object_id'')
class Nurse(models.Model):
hospital = models.ForeignKey(Hospital)
enrollement = GenericRelation(Enrollement)
class Pilot(models.Model):
plane = models.ForeignKey(plane)
enrollement = GenericRelation(Enrollement)
Cuando se serializan, me gustaría obtener algo como esto:
{
count: 50,
next: ''http...'',
previous: null,
results: [
{
type: "nurse",
hq: ''http://url/to/hq-detail/view'',
enrollement_date: ''2003-01-01 01:01:01'',
hospital: ''http://url/to/hospital-detail/view''
},
{
type: "pilot",
hq: ''http://url/to/hq-detail/view'',
enrollement_date: ''2003-01-01 01:01:01'',
plante: ''http://url/to/plane-detail/view''
},
]
}
Puedo hacerlo, y si es así, ¿cómo?
Puedo anidar una relación genérica, y podría publicar el proceso de serilizer.data para obtener lo que quiero, pero me pregunto si hay una mejor manera.
QUERIDOS AMIGOS DEL FUTURO: Al momento de escribir, el equipo del Marco de REST de Django parece estar trabajando para agregar un soporte más maduro para las relaciones genéricas. Pero aún no está terminado. Antes de copiar y pegar esta respuesta en su base de código, primero compruebe https://github.com/tomchristie/django-rest-framework/pull/755 para ver si se ha fusionado en el repositorio. Puede haber una solución más elegante que le espera. - Tu antiguo antepasado Tyler
Dado que está utilizando Django REST Framework , si desea hacer algo de postprocesamiento (aunque parezca reacio a hacerlo) puede lograr su objetivo anulando get_queryset
o list
en su vista. Algo como esto:
views.py:
from rest_framework.generics import ListAPIView
from rest_framework.response import Response
from models import *
from itertools import chain
class ResultsList(ListAPIView):
def list(self, request, *args, **kwargs):
nurses = Nurse.objects.all()
pilots = Pilot.objects.all()
results = list()
entries = list(chain(nurses, pilots)) # combine the two querysets
for entry in entries:
type = entry.__class__.__name__.lower() # ''nurse'', ''pilot''
if isinstance(entry, Nurse):
serializer = NurseSerializer(entry)
hospital = serializer.data[''hospital'']
enrollement_date = serializer.data[''enrollement.date'']
hq = serializer.data[''enrollement.hq'']
dictionary = {''type'': type, ''hospital'': hospital, ''hq'': hq, ''enrollement_date'': enrollement_date}
if isinstance(entry, Pilot):
serializer = PilotSerializer(entry)
plane = serializer.data[''plane'']
enrollement_date = serializer.data[''enrollement.date'']
hq = serializer.data[''enrollement.hq'']
dictionary = {''type'': type, ''plane'': plane, ''hq'': hq, ''enrollement_date'': enrollement_date}
results.append(dictionary)
return Response(results)
serializers.py
class EnrollementSerializer(serializer.ModelSerializer):
class Meta:
model = Enrollement
fields = (''hq'', ''enrollement_date'')
class NurseSerializer(serializer.ModelSerializer):
enrollement = EnrollementSerializer(source=''enrollement.get'')
class Meta:
model = Nurse
fields = (''hospital'', ''enrollement'')
class PilotSerializer(serializer.ModelSerializer):
enrollement = EnrollementSerializer(source=''enrollement.get'')
class Meta:
model = Pilot
fields = (''plane'', ''enrollement'')
La respuesta devuelta se vería así:
[
{
type: "nurse",
hq: "http://url/to/hq-detail/view",
enrollement_date: "2003-01-01 01:01:01",
hospital: "http://url/to/hospital-detail/view"
},
{
type: "pilot",
hq: "http://url/to/hq-detail/view",
enrollement_date: "2003-01-01 01:01:01",
plane: "http://url/to/plane-detail/view"
},
]
Notable:
- Mi serializers.py puede estar un poco fuera de lugar porque mi memoria de cómo representar relaciones genéricas en serializadores es un poco borrosa. YMMV.
- De forma similar a ^^, esto supone que serializers.py está en orden y ha configurado correctamente sus relaciones genéricas en línea con sus modelos.
- Hacemos
get
insource=enrollement.get
porque de lo contrario se devolverá un objeto GenericRelatedObjectManager si no especificamos una fuente. Eso es porque eso es lo que representa una relación genérica. El uso de.get
fuerza una consulta (como en la consulta QuerySet) que accede al modelo que establece como fuente de la relación genérica (en este caso,class Enrollement(models.Model)
. - Tenemos que usar
list(chain())
lugar de|
operador porque los conjuntos de consulta provienen de diferentes modelos. Es por eso que no podemos hacerentries = nurses | pilots
entries = nurses | pilots
. -
for entry in entries
seguramente puede hacerse más seco. GLHF.