缘由: Django 的 ORM 是惰性的每个用户访问网站时候,都要进行一次数据交互
在最初开发的时候,需要考虑到用户量大的时候,
又由于 Django 的 ORM 是惰性的,它只取出当前查询所需响应最小的数据。它不知道你是否有成百上千的相同或相似的数据也需要取出来。因此访问网站时这势必会对数据库造成巨大压力!
有句话说的是:只要你在序列化中使用嵌套关系,你就在拿你的性能开玩笑那么怎么解决他呢?
解决的方法是用户访问时候进行预加载功能,即将数据提前加载到用户本地中。如何预加载呢?其实django已经提供了方法,在这里我将工作中常用的加载方式贴出来:
很简单!在你访问量大的视图添加:
queryset = queryset.prefetch_related('你的序列化器名')
具体列子如下:
class CustomerSerializer(serializers.ModelSerializer):
orders = OrderSerializer(many=True, read_only=True)
def setup_eager_loading(cls, queryset):
""" Perform necessary eager loading of data. """
queryset = queryset.prefetch_related('orders')
return queryset
调用例子:
customer_qs = Customers.objects.all()
customer_qs = CustomerSerializer.setup_eager_loading(customer_qs) # Set up eager loading to avoid N+1 selects
post_data = CustomerSerializer(customer_qs, many=True).data
以上是简单实现预加载的原理,我想各位阅读预加载这块,代码经验应该还是有的吧??那我就直接贴出比较具体的代码块了,实现预加载功能!
- 首先创建一个简单的数据模型类:
from django.contrib.auth.models import User
class Event:
""" A single occasion that has many `attendees` from a number of organizations."""
creator = models.ForeignKey(User)
name = models.TextField()
event_date = models.DateTimeField()
class Attendee:
""" A party-goer who (usually) represents an `organization`, who may attend many `events`."""
events = models.ManyToManyField(Event, related_name='attendees')
organization = models.ForeignKey(Organization, null=True)
class Organization:
name = models.TextField()
2.预加载代码如下:
class EventSerializer(serializers.ModelSerializer):
creator = serializers.StringRelatedField()
attendees = AttendeeSerializer(many=True)
unaffiliated_attendees = AttendeeSerializer(many=True)
@staticmethod
def setup_eager_loading(queryset):
""" Perform necessary eager loading of data. """
# select_related for "to-one" relationships
queryset = queryset.select_related('creator')
# prefetch_related for "to-many" relationships
queryset = queryset.prefetch_related(
'attendees',
'attendees__organization')
# Prefetch for subsets of relationships
queryset = queryset.prefetch_related(
Prefetch('unaffiliated_attendees',
queryset=Attendee.objects.filter(organization__isnull=True))
)
return queryset