首页 > 解决方案 > 如何在 django 中使用外键创建新模型

问题描述

class Schedule(models.Model):
    name = models.CharField(max_length=50)


class ScheduleDefinition(models.Model):
    schedule = models.ForeignKey(Schedule, on_delete=models.DO_NOTHING)
    config = JSONField(default=dict, blank=True)

这些是我的模型。我正在尝试创建一个新ScheduleDefinition的(Schedule已经存在并且我知道要用于我的外键的 ID)。我有一个要使用的预定义计划 ID,但它不起作用..

发布此正文:

{
    "schedule_id": 1,
    "config": {
        "CCC": "ccc"
    }
}

我得到的错误: null value in column "schedule_id" violates not-null constraint

我究竟做错了什么?当我创建新ScheduleDefinition模型时,Schedule之前已经创建了模型。Schedule当我创造新的时,我永远不会创造新ScheduleDefinition的。

序列化器:

class ScheduleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Schedule
        fields = ['id', 'name']


class ScheduleDefinitionSerializer(serializers.ModelSerializer):
    schedule = ScheduleSerializer(read_only=True, many=False)

    class Meta:
        model = ScheduleDefinition
        fields = ['schedule', 'config']

看法:

from rest_framework import generics
from .models import Schedule, ScheduleDefinition
from .serializers import ScheduleSerializer, ScheduleDefinitionSerializer


class ScheduleList(generics.ListAPIView):
    queryset = Schedule.objects.all()
    serializer_class = ScheduleSerializer


class ScheduleDefinitionList(generics.ListCreateAPIView):
    queryset = ScheduleDefinition.objects.all()
    serializer_class = ScheduleDefinitionSerializer


class ScheduleDefinitionDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = ScheduleDefinition.objects.all()
    serializer_class = ScheduleDefinitionSerializer

查看错误:

File "/app/server/schedules/serializers.py", line 13, in ScheduleDefinitionSerializer
   schedule_id = serializers.PrimaryKeyRelatedField(source="schedule")
File "/usr/local/lib/python3.7/dist-packages/rest_framework/relations.py", line 247, in __init__
  super().__init__(**kwargs)
File "/usr/local/lib/python3.7/dist-packages/rest_framework/relations.py", line 108, in __init__
    'Relational field must provide a `queryset` argument, '
AssertionError: Relational field must provide a `queryset` argument, override `get_queryset`, or set read_only=`True`.

标签: pythondjango

解决方案


您已根据需要指定了 Schedule(非空),但实际上并未向其发布任何信息。目前,您的序列化程序需要以下形式的信息:

{
    "schedule": {
        "name": "Foo" 
    },
    "config": {...}
}

schedule_id发布时被丢弃。此外,您已指定这schedule是一个只读字段,这意味着即使您发布了时间表,它仍然会被丢弃。

如果您想发布到外键,您需要通过手动编写可写嵌套序列化程序的创建/更新逻辑来专门处理它(这可能有点麻烦),或者使用不同的(可写)外键字段序列化器并以另一种方式序列化您的其他只读数据。

例如,以下设置应该与您当前尝试发布的数据一起工作(未经测试):

class ScheduleDefinitionSerializer(serializers.ModelSerializer):
    schedule = serializers.PrimaryKeyRelatedField(
        queryset=Schedule.objects.all()
    )
    schedule_name = serializers.CharField(read_only=True, source="schedule.name")

    class Meta:
        model = ScheduleDefinition
        fields = ['schedule', 'schedule_name', 'config']

schedule_name有了这个,您的帖子应该可以工作,并且您仍然可以通过列表/详细信息视图中的字段对相应的日程安排名称进行只读访问。


编辑

我早期版本的代码与原始所需的 POST 数据不兼容。以下应该可以在不更改 POST 的情况下工作

class ScheduleDefinitionSerializer(serializers.ModelSerializer):
    schedule = ScheduleSerializer(many=False, read_only=True)
    schedule_id = serializers.PrimaryKeyRelatedField(
        source="schedule",
        queryset=Schedule.objects.all()
    )

    class Meta:
        model = ScheduleDefinition
        fields = ['schedule', 'schedule_id', 'config']

推荐阅读