0π
I would recommend using GraphQL/DataLoaders to solve this N+1 problem as DRF is not well suited for it. However, this can be done in DRF by using a custom ListSerializer (django creates one for you behind the scenes automatically) and overloading the to_representation functions of both List/Child serializers:
class SchoolListSerializer(serializers.ListSerializer):
def to_representation(self, data):
iterable = data.all() if isinstance(data, models.Manager) else data
keys = [(item.id, item.location) for item in iterable]
# perform your bulk nearby query here using the id/locations
# the result should be a dict with school id keys and list of serialized hospital values
# {1: [hospital.to_dict(), hospital.to_dict(), ...], ...}
nearby_by_id = ...
extra = {
'nearby_hospitals_by_id': nearby_by_id
}
return [
self.child.to_representation(item, **extra) for item in iterable
]
class SchoolSerializer(serializers.ModelSerializer):
class Meta:
model = School
fields = ('location', )
list_serializer_class = SchoolListSerializer
def to_representation(self, instance, **extra):
response = super().to_representation(instance)
response['nearby_hospitals'] = extra['nearby_hospitals_by_id'][instance.id]
return response
I left out the actual DB query, however the example will work with any queries regardless of where the data resides.
π€Bemis
-1π
Iβm not sure itβs better, but I think you are taking the problem in the reverse direction. I see no reason for any JOIN at all.
class SchoolSerializer(serializers.ModelSerializer):
nearby_hospitals = serializers.SerializerMethodField('get_nearby_hospitals')
class Meta:
model = School
fields = ('location', 'nearby_hospitals',)
def get_nearby_hospitals(self, obj):
geom = obj.location
try:
# why do you query School model if you want nearby hospitals?
locations = Hospital.objects.filter(location__distance_lte=(geom ,10000))
return locations # not sure it's the good type to return though
except:
return
π€Benjamin Toueg
Source:stackexchange.com