tutorial sirve queryset que primarykeyrelatedfield para framework foreign entre diferencia django rest serialization django-rest-framework generic-relations

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 in source=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 hacer entries = nurses | pilots entries = nurses | pilots .
  • for entry in entries seguramente puede hacerse más seco. GLHF.