ModelSerializer在Django REST框架中非常慢

时间:2015-03-12 17:52:15

标签: django django-rest-framework django-orm

我正在为我的API使用Django REST框架,昨天我想看看它如何适用于大数据。我找到this tutorial关于如何描述您的请求(由Tom Christie编写),我发现对于10,000个用户,我的请求在2:20分钟内惊人地发布。

大部分时间用于序列化对象(大约65%),所以我想知道我该怎样做才能加快速度?

我的用户模型实际上正在扩展默认的django模型,因此使用.values()不起作用,因为我也没有获得嵌套模型(即使速度更快)。

非常感谢任何帮助:)

修改

我在检索查询集时已经使用了.select_related(),并且它已经改善了我的时间,但只有几秒钟。总查询的数量是10,所以我的问题不在于数据库访问。

另外,我使用.defer(),以避免在此请求中不需要的字段。这也提供了一个小的改进,但还不够。

编辑#2

Models

from django.contrib.auth.models import User
from django.db.models import OneToOneField
from django.db.models import ForeignKey

from userena.models import UserenaLanguageBaseProfile
from django_extensions.db.fields import CreationDateTimeField
from django_extensions.db.fields import ModificationDateTimeField

from mycompany.models import MyCompany


class UserProfile(UserenaLanguageBaseProfile):
    user = OneToOneField(User, related_name='user_profile')
    company = ForeignKey(MyCompany)
    created = CreationDateTimeField(_('created'))
    modified = ModificationDateTimeField(_('modified'))

Serializers

from django.contrib.auth.models import User

from rest_framework import serializers

from accounts.models import UserProfile


class UserSerializer(serializers.ModelSerializer):
    last_login = serializers.ReadOnlyField()
    date_joined = serializers.ReadOnlyField()
    is_active = serializers.ReadOnlyField()

    class Meta:
        model = User
        fields = (
            'id',
            'last_login',
            'username',
            'first_name',
            'last_name',
            'email',
            'is_active',
            'date_joined',
        )


class UserProfileSerializer(serializers.ModelSerializer):
    user = UserSerializer()

    class Meta:
        model = UserProfile
        fields = (
            'id',
            'user',
            'mugshot',
            'language',
        )

Views

class UserProfileList(generics.GenericAPIView,
                      mixins.ListModelMixin,
                      mixins.CreateModelMixin):

    serializer_class = UserProfileSerializer
    permission_classes = (UserPermissions, )

    def get_queryset(self):
        company = self.request.user.user_profile.company
        return UserProfile.objects.select_related().filter(company=company)

    @etag(etag_func=UserListKeyConstructor())
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

3 个答案:

答案 0 :(得分:9)

几乎所有性能问题都来自N + 1个查询。这通常是因为您正在引用相关模型,并且生成每个对象的每个关系的单个查询以获取信息。您可以使用.select_related方法as described in my other Stack Overflow answer中的.prefetch_relatedget_queryset来改善这一点。

同样的提示Django provides on database optimization也适用于Django REST框架,所以我建议也要考虑这些。

您在序列化期间看到性能问题的原因是因为这是Django向数据库发出查询的时间。

答案 1 :(得分:5)

我知道这已经过时了,你可能已经解决了你的问题......但对于其他任何人来说都是这篇文章......

问题是你在做盲人

select_related()

没有参数,对您的查询绝对没有任何参数。你真正需要做的是

prefetch_related('user_profile')

没有详细说明, select_related 用于“一对”关系,而 prefetch_related 用于“到多个”关系。在您的情况下,您使用的是反向关系,这是一个“to many”查询。

您的另一个问题是您没有正确使用反向关系。将序列化程序中的get_queryset()更改为this,我认为你会得到你想要的东西:

def get_queryset(self):
    return UserProfile.objects.prefetch_related('user_profile').all()

答案 2 :(得分:2)

ModelSerializers 很慢,你自己说的。以下是有关其发生原因以及如何加快处理速度的更多信息:https://hakibenita.com/django-rest-framework-slow

<块引用>
  • 在性能关键端点中,使用“常规”序列化程序,或者根本不使用。
  • 不用于写入或验证的序列化程序字段应为只读。