如何编写一个django-rest-framework序列化器/字段来合并来自泛型关系的数据?

时间:2013-05-28 13:40:45

标签: django rest serialization django-rest-framework generic-relations

我的对象具有指向各种其他对象的泛型关系,我需要将它们合并(内联),以便序列化对象看起来像一个完整的对象。

E.G:

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)

当序列化时,我想得到这样的东西:

{
    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'

        },
    ]
}

我可以这样做,如果可以,怎么做?

我可以nest一般关系,我可以发布serilizer.data来获得我想要的东西,但我想知道是否有更好的方法。

1 个答案:

答案 0 :(得分:37)

来自未来的亲朋好友:在撰写本文时,Django REST Framework团队似乎正致力于为通用关系添加更成熟的支持。但它还没有完成。在将此答案复制粘贴到您的代码库之前,首先检查https://github.com/tomchristie/django-rest-framework/pull/755以查看它是否已合并到repo中。可能有更优雅的解决方案等待着您。 - 你的古老祖先泰勒

鉴于您正在使用Django REST Framework,如果 希望进行一些后处理(即使您似乎犹豫不决),您可以通过覆盖{{1}来实现目标您视图中的{}或get_queryset。像这样:

views.py:

list

serializers.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)

返回的响应如下:

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')

值得注意的:

  • 我的serializers.py可能有点偏离,因为我对如何在序列化器中表示泛型关系的记忆有点模糊。 YMMV。
  • 与^^类似,这假设您的serializers.py已按顺序排列,并已根据您的模型正确设置其通用关系。
  • 我们在 [ { 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" }, ] 中执行get,否则如果我们不指定源,则会返回GenericRelatedObjectManager对象。那是因为这是一般关系所代表的。使用source=enrollement.get强制查询(如在QuerySet查询中),该查询访问您设置为通用关系源的模型(在本例中为.get
  • 我们必须使用class Enrollement(models.Model)而不是list(chain())运算符,因为查询集来自不同的模型。这就是我们无法做|
  • 的原因
  • entries = nurses | pilots肯定会变得更加干燥。 GLHF。