38👍
✅
DEAR FRIENDS FROM THE FUTURE: At time of writing, the Django REST Framework team seems to be working on adding more mature support for generic relations. But it is not yet finished. Before copy-pasting this answer into your code base, check https://github.com/tomchristie/django-rest-framework/pull/755 first to see if it’s been merged into the repo. There may be a more elegant solution awaiting you. — Your ancient ancestor Tyler
Given you’re using Django REST Framework, if you did want to do some post-processing (even though you seem hesitant to) you can accomplish something your goal by overriding get_queryset
or list
in your view. Something like this:
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')
Returned response would look like:
[
{
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"
},
]
Noteworthy:
- My serializers.py may be a bit off here because my memory of how to represent generic relations in serializers is a bit foggy. YMMV.
- Similarly to ^^ this assumes your serializers.py is in order and has properly set up its generic relationships in line with your models.
- We do the
get
insource=enrollement.get
because otherwise a GenericRelatedObjectManager object will be returned if we don’t specify a source. That’s because that’s what a generic relation represents. Using.get
forces a query (as in QuerySet query) which accesses the model you set as the source of the generic relation (in this case,class Enrollement(models.Model)
. - We have to use
list(chain())
instead of the|
operator because the querysets come from different models. That’s why we can’t doentries = nurses | pilots
. for entry in entries
can surely be made more dry. GLHF.
Source:stackexchange.com