REST Framework 中相关对象的问题

Problem with related objects in REST Framework

我有一个简单的 django 应用程序,具有以下模型:

class Product(models.Model):
    __metaclass__ = ABCMeta

    title = models.CharField(max_length=50)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    slug = models.SlugField(max_length=100, unique=True)
    price = models.IntegerField()
    is_published = models.BooleanField(default=True)

    @abstractmethod
    def __str__(self):
        pass

    @abstractmethod
    def get_absolute_url(self):
        pass


class SupplyType(models.Model):
    title = models.CharField(max_length=10)
    slug = models.SlugField(max_length=100, unique=True)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('supply_type_detail', kwargs={'slug': self.slug})


class Processor(Product):
    supply_type = models.ForeignKey(SupplyType, on_delete=models.CASCADE)
    cores_amount = models.IntegerField()
    threads_amount = models.IntegerField()
    technological_process = models.IntegerField()

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('processor_detail', kwargs={'slug': self.slug})

为它们编写了相应的序列化程序:

class SupplyTypeSerializer(ModelSerializer):
    class Meta:
        model = SupplyType
        fields = '__all__'


class ProcessorSerializer(ModelSerializer):
    class Meta:
        model = Processor
        fields = '__all__'
        depth = 1

也写了相应的观点(我只举创作的观点举例):

class ProcessorCreateAPIView(CreateAPIView):
    model = Processor
    serializer_class = ProcessorSerializer


class SupplyTypeCreateAPIView(CreateAPIView):
    model = SupplyType
    serializer_class = SupplyTypeSerializer

当我尝试使用 POST 请求添加“供应类型”时,它成功运行。

但是,当我尝试添加这样的处理器时:

{
    "title": "Intel Pentium Gold G6400",
    "slug": "intel-pentium-gold-g6400",
    "price": 19690,
    "is_published" : true,
    "cores_amount": 2,
    "threads_amount": 4,
    "technological_process": 14,
    "supply_type": 1
}

我得到一个错误:

django.db.utils.IntegrityError:关系“store_processor”的列“supply_type_id”中的空值违反了非空约束 详细信息:失败的行包含 (1, 2, 4, 14, null).

最终,存在以下问题:如何解决这个问题,以及如何在这种情况下通过 API(仍然通过 id)或其他方式添加具有所需电源类型的处理器方式?

因此,当我做一个 GET 请求时,我想得到这样的东西:

{
    "title": "Intel Pentium Gold G6400",
    "slug": "intel-pentium-gold-g6400",
    "price": 19690,
    "is_published" : true,
    "cores_amount": 2,
    "threads_amount": 4,
    "technological_process": 14,
    "supply_type": 
    {
        "id": 1,
        "title": "OEM",
        "slug": "oem"
    }

是的,对不起我的英语。

您需要使用嵌套序列化程序的概念。见下面代码

class ProcessorSerializer(ModelSerializer):
    supply_type = SupplyTypeSerializer()

    class Meta:
        model = Processor
        fields = '__all__'

因此,当您执行 GET 请求时,您会得到如下内容:

{
    "title": "Intel Pentium Gold G6400",
    "slug": "intel-pentium-gold-g6400",
    "price": 19690,
    "is_published" : true,
    "cores_amount": 2,
    "threads_amount": 4,
    "technological_process": 14,
    "supply_type": {
        "id": 1,
        "title": "OEM",
        "slug": "oem"
    }
}

为了创建处理器,您必须传递 supply_type dict 对象,类似于您在输出中获得的对象。但是由于您想传递 supply_type id,您可以按如下方式覆盖 to_internal_value 方法并设置 supply_type 字段为 read_only:

def to_internal_value(self, data):
    supply_type_id = data.get('supply_type')
    internal_data = super().to_internal_value(data)
    try:
        supply_type = SupplyType.objects.get(id=supply_type_id)
    except SupplyType.DoesNotExist:
        raise serializers.ValidationError(
            {'supply_type': ['Item does not exist']},
        )
    internal_data['supply_type'] = supply_type
    return internal_data

现在您可以像这样创建一个处理器:

{
    "title": "Intel Pentium Gold G6400",
    "slug": "intel-pentium-gold-g6400",
    "price": 19690,
    "is_published" : true,
    "cores_amount": 2,
    "threads_amount": 4,
    "technological_process": 14,
    "supply_type": 1
}

最终代码:

class ProcessorSerializer(serializers.ModelSerializer):
    supply_type = SupplyTypeSerializer(read_only=True)

    class Meta:
        model = Processor
        fields = '__all__'

    def to_internal_value(self, data):
        supply_type_id = data.get('supply_type')
        internal_data = super().to_internal_value(data)
        try:
            supply_type = SupplyType.objects.get(id=supply_type_id)
        except SupplyType.DoesNotExist:
            raise serializers.ValidationError(
                {'supply_type': ['Item does not exist']},
            )
        internal_data['supply_type'] = supply_type
        return internal_data