Home > OS >  Django Rest Framework - display child value on parent serializer without making too many extra queri
Django Rest Framework - display child value on parent serializer without making too many extra queri

Time:10-12

I have this two models:

class Parent(models.Model):
  name = models.CharField(max_length=255)
  level = models.IntegerField()
  
  
class Child(models.Model):
  parent = models.ForeignKey(Parent, related_name='children')
  therefore_name = models.CharField(max_length=255)
  level = models.IntegerField()
  active_from = models.DateTimeField(auto_now_add=True)
  active_to = models.DateTimeField(null=True, blank=True)

Child model is used to be able to "overwrite" values on parent, and there is validation to prevent a parent with multiple overlapping children with the same active_from and active_to dates.

My view:

class FacilityViewSet(viewsets.ReadOnlyModelViewSet):
  serializer_class = ParentSerializer

  def get_queryset(self):
    now = timezone.now()
    parents = Parent.objects.all().prefetch_related(
      Prefetch('children', queryset=Child.objects.exclude(valid_from__gt=now, valid_from__isnull=False).exclude(valid_to__lt=now, valid_to__isnull=False).distinct())
    )
    return parents

My serializer:

class ParentSerializer(serializers.ModelSerializer):
  class Meta:
    model = Parent
    fields = ['id']

  def to_representation(self, instance):
    representation = super().to_representation(instance)

    if hasattr(instance, 'children') and instance.children.exists():
      child = instance.children.first()
    else:
      child = Child(therefore_name=instance.name, level=instance.level)

    representation['name'] = child.therefore_name
    representation['level'] = child.level

    return representation

This works, but the code makes alot of extra queries. Is there something I could do to cut the queries down?

This is the code that is makes extra queries:

if hasattr(instance, 'children') and instance.children.exists():
  child = instance.children.first()

CodePudding user response:

In the ParentSerializer.to_representation(), there is no need to call instance.children.exists() first. Just call instance.children.first() and if no child exists it will be None.

CodePudding user response:

The database is already hit on prefetch, so this does not query anything extra:

child = None

for child in instance.children.all()[:1]:
  child = child

if not child:
  child = Child(therefore_name=instance.name, level=instance.level)
  • Related