我有几种具有不同模型的车辆类型(汽车,飞机,火车),并且希望有一个API端点,该端点将为我提供所有组合模型的可过滤列表。
我已经修改了ViewSet的list方法,以合并每个模型ModelViewSet的序列化结果,并通过一个端点提供它们。响应的格式正确,但是我希望能够对其进行过滤。
我已经尝试使用约50,000个随机生成的载具(均匀分布在模型中)对端点进行了测试,未过滤的响应可能会非常缓慢。
当前回复格式:
{
"Car": [
{
"url": "http://127.0.0.1:8000/myapp/api/cars/1/",
"name": "Mitsuoka",
"ground_clearance": null,
"road_legal": true,
"active": true,
"bought_by": null
}
],
"Train": [
{
"url": "http://127.0.0.1:8000/myapp/api/trains/1/",
"name": "What",
"freight_capacity": null,
"wheel_config": null,
"active": false,
"bought_by": null
},
{
"url": "http://127.0.0.1:8000/myapp/api/trains/2/",
"name": "Manufacturer",
"freight_capacity": null,
"wheel_config": null,
"active": false,
"bought_by": null
}
],
"Plane": []
}
所需过滤器示例:
代码
models.py
from django.db import models
class Buyer(models.Model):
name = models.CharField(unique=True, max_length = 20)
class Car(models.Model):
name = models.CharField(unique=True, max_length = 50)
ground_clearance = models.CharField(unique=True, max_length = 50, null=True, blank=True)
road_legal = models.BooleanField(default=True)
active = models.BooleanField(default=True)
bought_by = models.ForeignKey(Buyer, null=True, blank=True, to_field="name", related_name="cars")
class Plane(models.Model):
name = models.CharField(unique=True, max_length = 50)
max_altitude = models.CharField(unique=True, max_length = 50, null=True, blank=True)
cruising_speed = models.CharField(unique=True, max_length = 50, null=True, blank=True)
active = models.BooleanField(default=True)
bought_by = models.ForeignKey(Buyer, null=True, blank=True, to_field="name", related_name="planes")
class Train(models.Model):
name = models.CharField(unique=True, max_length = 50)
freight_capacity = models.CharField(unique=True, max_length = 50, null=True, blank=True)
wheel_config = models.CharField(unique=True, max_length = 50, null=True, blank=True)
active = models.BooleanField(default=True)
bought_by = models.ForeignKey(Buyer, null=True, blank=True, to_field="name", related_name="trains")
views.py
from rest_framework import viewsets
from rest_framework.response import Response
from myapp import models, serializers
class ListVehicles(viewsets.ViewSet):
def list(self, request, format=None):
models_serializers = {
models.Car: serializers.CarSerializer,
models.Plane: serializers.PlaneSerializer,
models.Train: serializers.TrainSerializer,
}
cars = models.Car.objects.select_related('bought_by')
trains = models.Train.objects.select_related('bought_by')
planes = models.Plane.objects.select_related('bought_by')
queries_list = list()
queries_list.extend((cars, planes, trains))
serializer_context = {'request': request}
serialized_querysets = dict()
for queryset in queries_list:
for model, serializers in models_serializers.items():
if queryset.model == model:
serialized_querysets[model.__name] = serializer(queryset, context=serializer_context, many=True).data
return Response(serialized_querysets)
...
# for each vehicle there also exists an individual ModelViewSet, e.g.,:
class CarViewSet(viewsets.ModelViewSet):
'''
API endpoint that allows Cars to be viewed or edited.
'''
queryset = models.Car.objects.select_related('bought_by')
serializer_class = serializers.CarSerializer
filterset_fields = ('bought_by','active')
...
...
我修改了this method,以遍历Queryset并添加到serialized_querysets字典中,而不是遍历每个模型实例并附加到serialized_querysets列表上。随着数据集的增加,遍历三种车辆类型的每个模型实例变得非常慢。
serializers.py
from rest_framework import serializers
from myapp import models
class CarSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.Car
fields = '__all__'
extra_kwargs = {'url': {'view_name': 'myapp:car-detail'}}
class TrainSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.Train
fields = '__all__'
extra_kwargs = {'url': {'view_name': 'myapp:train-detail'}}
class PlaneSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.Plane
fields = '__all__'
extra_kwargs = {'url': {'view_name': 'myapp:plane-detail'}}
urls.py
from myapp import views
from django.urls import include, path
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r'vehicles', views.ListVehicles, base_name='vehicles')
...
...