Michael Bykovski
Michael Bykovski

Reputation: 113

Django Rest Framework - Nested Serializer are lazy loaded?

I am lovely using Django Rest Framework and have a lot of fun with it. But there is one thing which disturbes me. I have a Model and in this Model are a lot of Foreignkeys. i.e:

class Order(models.Model):
    bought_by = models.ForeignKey(User, related_name='bought_orders')
    bought_on = models.DateTimeField(default=datetime.datetime.now, blank=True)
    category = models.ForeignKey(OrderCategory, related_name='orders')
    article = models.ForeignKey(Article, related_name='orders')
    supplier = models.ForeignKey(Supplier, related_name='orders')
    purpose = models.CharField(null=True, blank=True, max_length=255)
    payment_method = models.ForeignKey(PaymentMethod, related_name='orders')
    order_number = models.CharField(max_length=255)
    delivery_received_on = models.DateTimeField(null=True, blank=True)
    delivery_received_by = models.ForeignKey(User, null=True, blank=True, related_name='received_orders')
    tags = TaggableManager(blank=True)

so I use the good ModelSerializer and by the way I use nested serializer i.e.:

class ReadOrderSerializer(ModelSerializer):
    created = DateTimeField()
    updated = DateTimeField()
    bought_by = UserSerializer()
    category = OrderCategorySerializer()
    article = ArticleSerializer()
    supplier = SupplierSerializer()
    payment_method = PaymentMethodSerializer()
    tags = TagListSerializerField()
    invoice_documents = InvoiceDocumentSerializer(many=True)

The problem is that the request takes about 1.7 seconds for only 50 order. Okay, that was unexpected... I opened my Django debug tool and looked at the sql statements. Django Rest Framework or Django opens for every order a new connection and do a select statement.

Is there a possible way to walk around the problem? Turn off lazy loading or something I can change in my serializers?

Thank you very much!

Upvotes: 3

Views: 2794

Answers (1)

Todor
Todor

Reputation: 16050

Your problem comes from the queryset, not the serializer. By default Django querysets do not follow relations and so the related fields are not populated. In order to fix that you have to change your queryset to use select_related for OneToOne and ForeignKey fields and prefetch_related for ManyToMany fields.

So lets say you are using DRF ViewSets, you can change your get_queryset method in the OrderViewSet to something like that:

def get_queryset(self):
    return Order.objects.select_related(
            'bought_by', 'category', 'article', 'supplier',
            'payment_method', 'delivery_received_by'
        ).prefetch_related(
            'tags', 'invoice_documents'
        )

Upvotes: 8

Related Questions