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)