【问题标题】:ForeignKey is null after POST in Django Rest (Nested Serializer)在 Django Rest(嵌套序列化程序)中 POST 后 ForeignKey 为空
【发布时间】:2020-07-04 21:21:26
【问题描述】:

我是 Django 的新手,我已经实现了一对多的关系,但是嵌套的一个字段为空。

当我发布 destinations 在响应部分中为空。以下是我的回复部分:

{
    "id": 7,
    "name": "Germany tour",
    "description": "This is a fascinating tour to take",
    "price": "30.0",
    "destinations": null,
    "capacity": 10
}

这是我在邮递员的正文部分发帖的方式:

{
    "name": "Germany tour",
    "description": "This is a fascinating tour to take",
    "price": 30.0,
    "destinations": [
        {
            "location":"Germany",
            "tour_type":"Adventure",
            "danger_type":"Medium"
        }
],
    "capacity": 10
}

然后,下面是我的 models 文件:

from django.db import models


class Destinations(models.Model):
    location = models.CharField(max_length=20)
    tour_type = models.CharField(max_length=20)
    danger_type = models.CharField(max_length=20)

    class Meta:
        unique_together = ['location', 'tour_type']


class TourPackages(models.Model):
    name = models.CharField(max_length=50)
    description = models.TextField()
    price = models.DecimalField(max_digits=9, decimal_places=1)
    destinations = models.ForeignKey(Destinations, related_name="destinations", on_delete=models.CASCADE)
    capacity = models.IntegerField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.name

然后,我的 serializers 文件:

from rest_framework import serializers
from .models import TourPackages, Destinations


class DestinationSerializer(serializers.ModelSerializer):
    class Meta:
        model = Destinations
        fields = ['tour_type', 'danger_type']


class TourPackagesSerializer(serializers.ModelSerializer):
    destinations = DestinationSerializer(many=True)

    class Meta:
        model = TourPackages
        fields = ['id', 'name', 'description', 'price', 'destinations', 'capacity']

    def create(self, validated_data):
        destination_data = validated_data.pop("destinations")
        location = TourPackages.objects.create(**validated_data)

        for dest_data in destination_data:
            Destinations.objects.create(location=location, **dest_data)

        return location

最后是我的 views 文件:

from rest_framework import generics

from .models import TourPackages
from .serializer import TourPackagesSerializer


class TourList(generics.ListCreateAPIView):
    queryset = TourPackages.objects.all()
    serializer_class = TourPackagesSerializer


class TourDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = TourPackages.objects.all()
    serializer_class = TourPackagesSerializer

我想要的是发布所有数据并返回响应

【问题讨论】:

    标签: python python-3.x django django-rest-framework


    【解决方案1】:

    您需要先创建Destinations 对象,以便在ForeignKey 的情况下分配它们。从您发布的示例数据来看,这意味着您可以拥有多个 destinations 并且您在其上设置了 on_delete=models.CASCADE。假设对于一个特定的旅行,您有4 目的地并且您决定删除其中两个,那么models.CASCADE 将尝试删除您的tours 对象。如果发生这种情况,剩余的2 目的地对象将指向哪里? Database integrity 将丢失。所以Django 不允许这样做。您可以通过将ForeignKey 更改为ManyToManyField 来修复。 而你的TourPackagesSerializer 应该是这样的:

    基于 Ananya 的回答:

    class TourPackagesSerializer(serializers.ModelSerializer):
        destinations = DestinationSerializer(many=True)
    
        class Meta:
            model = TourPackages
            fields = ['id', 'name', 'description', 'price', 'destinations', 'capacity']
    
        def create(self, validated_data):
            destination_data = validated_data.pop('destinations')
            dest_obj_list = []
            for dest_data in destination_data:
                dest_obj = Destinations.objects.create(**dest_data)
                dest_obj_list.append(dest_obj)
            location = TourPackages.objects.create(**validated_data)
            location.destinations.set(dest_obj_list)
            location.save()
            return location
    

    【讨论】:

    • 非常感谢,你救了我的命。
    • 虽然我认为仍在努力区分或何时使用多对多和)ne-to-many。欢迎任何见解
    • 你可以看看这个question
    【解决方案2】:

    在 create 方法中,您正在创建目标对象,但未在位置设置外键。试试这个:

    def create(self, validated_data):
        destination_data = validated_data.pop('destinations')
        dest_obj_list = []
        for dest_data in destination_data:
            dest_obj = Destinations.objects.create(location=location, **dest_data)
            dest_obj_list.append(dest_obj)
        location = TourPackages.objects.create(**validated_data)
        location.destinations.set(dest_obj_list)
        location.save()
    

    【讨论】:

    • set 方法不适用于ForeignKeydocs。加上Destinations.objects.create(location=location, **dest_data) 也会报错,因为location 对象还没有被创建。
    猜你喜欢
    • 1970-01-01
    • 2020-03-21
    • 2021-10-19
    • 2018-05-19
    • 2014-08-20
    • 2019-12-23
    • 2016-02-09
    • 2018-07-06
    • 1970-01-01
    相关资源
    最近更新 更多