Reputation: 2308
For my project I started to use Laravel for the api than I switched to Django / django rest framework, I did this to gain more speed as I need to query large data.
Now I got the following situation: I got a "Group" which has "Subjects" and which has a recursive relation.
Now a group can have like 2000+ subjects(including the descendent subjects) a parent subject has +/- 30 subjects.
This is my code:
serializers
class RecursiveField(serializers.Serializer):
def to_representation(self, value):
serializer = self.parent.parent.__class__(value, context=self.context)
return serializer.data
class SubjectSerializer(serializers.ModelSerializer):
parent_of = RecursiveField(many=True, read_only=True)
class Meta:
model = Subject
fields = ("id", "name", "parent_of", "parent")
class GroupSerializer(serializers.ModelSerializer):
subjects = SubjectSerializer(many=True, read_only=True)
class Meta:
model = Group
fields = ("id", "name", "subjects")
def setup_eager_loading(cls, queryset):
return queryset.prefetch_related("subjects")
views
class GroupViewSet(ModelViewSet):
class Paginator(BasePaginator):
model = Group
queryset = Group.objects.all()
serializer_class = serializers.GroupSerializer
pagination_class = Paginator
def get_queryset(self):
return self.get_serializer().setup_eager_loading(GroupViewSet.queryset)
I tested the same request with the laravel api and its much faster, still noticeable slow but its ok(5-10 secs). With django rest framework its too slow (1 minute +/-), and thats just a page with 1 group that has 2500 subjects.
I do know what takes long, the RecursiveField class, because when I remove that the query is done in less than 2 seconds. So my question is whats the main cause, because it's creates a recursive relation (I doubt)? Or is it because I don't prefetch?
And ofcourse whats the best way to do this?
Thank you
Upvotes: 1
Views: 904
Reputation: 1971
The problem is not DRF, but the data structure itself.
It is very slow in django
to query all ancestors/descendants recursively, your should use a more efficient data structure.
For the same reason I wrote django-treenode
, it performs tree operations without query the db.
You can read the docs here: https://github.com/fabiocaccamo/django-treenode
Upvotes: 0
Reputation: 13731
You have a few options, but I don't think any are great. Recursive queries aren't very well supported with Django.
root
ForeignKey to Subject on Subject that would identify the root subject. This would allow you to grab all subjects in a tree fairly easily. Then you'd have to arrange them in your View/Viewset to fit the ordering (if that's necessary).raw()
and your database's recursive functionality to fetch the models. This would require raw SQL and can be painful to maintain.django_cte
. I've used this in one of my projects for a few queries, but I'm not a big fan of it. It breaks some functionality with update()
being called on an empty queryset. However, it will work and it won't require you to drop down to raw SQL. Upvotes: 1