合并和过滤不相关的模型

时间:2019-04-21 05:56:00

标签: python django django-rest-framework django-rest-framework-filters

我有几种具有不同模型的车辆类型(汽车,飞机,火车),并且希望有一个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')

...
...

0 个答案:

没有答案