У меня есть несколько типов транспортных средств (автомобили, самолеты, поезда) с разными моделями, и я хочу иметь конечную точку API, которая даст мне фильтруемый список всех моделей вместе взятых.
Я изменил метод списка ViewSet, чтобы объединить сериализованные результаты каждой модели 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')
...
...
Я изменил этот метод , чтобы выполнить итерацию по 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')
...
...