如何使用来自相关模型的新信息字段注释查询集?

How to annotate a queryset with a new field of information from a related model?

我有一个模型,其中 Vehicle table 有更多 Wheels table。我试图在单个字段中显示相关车轮 table 中车辆和第一个车轮的信息。我已经看到 F 函数可能有用,但我找不到正确的配置让它工作。 table 通过另一个名为 colour 的字段关联,该字段在 Wheels table.

中声明为外键

    class VehicleListView(ListView):
        template_name = 'vehicle.html'
        queryset = Vehicle.objects.all()

        queryset = queryset.annotate(wheel1_name = F('Wheels__wheel_name'))

        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            return context

我想要


    queryset = queryset.annotate(wheel1_name = F('Wheels__wheel_name'))

到 return 每辆车的第一个车轮名称的列表,这样我就可以遍历它并在 table.

中显示
models.py

class Vehicle(models.Model):
    vehicle_id = models.AutoField(primary_key=True)
    vehicle_name = models.CharField(max_length=100)
    color = models.CharField(max_length=100)

class Wheels(models.Model):
    wheels_id = models.AutoField(primary_key=True)
    color = models.ForeignKey(Vehicle, null=True, on_delete=models.SET_NULL,
                                  db_column='color')
    wheel_name = models.CharField(max_length=100)

所以我稍微更改了你的代码,设置了数据库,创建了 2 个 Vehicle 个对象,每个对象有 2 个相关的 Wheels 个对象,所以总共有 4 个 Wheels 个对象。

我为某个 Vehicle 对象的第一个相关 Wheel 对象添加了一个函数 queries

# models.py

class Vehicle(models.Model):
    vehicle_id = models.AutoField(primary_key=True)
    vehicle_name = models.CharField(max_length=100)
    color = models.CharField(max_length=100)

    # this function returns a slice of the resulting queryset which contains
    # the first related Wheels object for each Vehicle object
    def get_first_wheels(self):
        return Wheels.objects.filter(color=self).order_by('wheels_id')[:1]


class Wheels(models.Model):
    wheels_id = models.AutoField(primary_key=True)
    color = models.ForeignKey(Vehicle, null=True, on_delete=models.SET_NULL)
    wheel_name = models.CharField(max_length=100)

我使用 Django serializers to serialize the data. To get the first related Wheels object I used a SerializerMethodField() 调用 models.py 中的 get_first_wheels() 函数,如下所示:

# serializers.py

class WheelsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Wheels
        fields = ('wheels_id', 'color', 'wheel_name')


class VehicleSerializer(serializers.ModelSerializer):
    first_wheel = serializers.SerializerMethodField(read_only=True)

    def get_first_wheel(self, model):
        qs = model.get_first_wheels()
        return WheelsSerializer(qs, many=True).data

    class Meta:
        model = Vehicle
        fields = ('vehicle_id', 'vehicle_name', 'color', 'first_wheel')

我稍微改变了你的看法,改用了 ModelViewSet

# views.py

class VehicleViewSet(viewsets.ModelViewSet):
    serializer_class = VehicleSerializer
    queryset = Vehicle.objects.all()

我去使用 DefaultRouter() 注册端点,如下所示:

# urls.py

from rest_framework import routers
# import ViewSet here

router = routers.DefaultRouter()

router.register(r'vehicles`, views.VehicleViewSet, base_name='vehicle')

然后我运行下面的命令:

  • manage.py makemigrations

  • manage.py migrate

  • manage.py runserver

我创建了 2 个 Vehicle 个对象,每个对象有 2 个相关的 Wheels 个对象。

当我在浏览器中转到 http://127.0.0.1:8000/vehicles/ 时,它 returns 所有 Vehicle 对象及其第一个相关的 Wheels 对象,如下所示:

[
    {
        "vehicle_id": 1,
        "vehicle_name": "BMW",
        "color": "Blue",
        "first_wheel": [
            {
                "wheels_id": 1,
                "color": 1,
                "wheel_name": "BMW1"
            }
        ]
    },
    {
        "vehicle_id": 2,
        "vehicle_name": "Ferrari",
        "color": "Red",
        "first_wheel": [
            {
                "wheels_id": 3,
                "color": 2,
                "wheel_name": "Ferrari1"
            }
        ]
    }
]