Django POST验证字段消失(NOT NULL约束失败)

时间:2020-07-27 14:06:48

标签: python django rest post notnull

我有一个带有某些模型的Django项目。麻烦我的是这个:

class Job(models.Model):
    patient = models.CharField(max_length=64, null=False, blank=False)
    how = MultiSelectField(choices=HOW_CHOICES, default=1)
    with_who = MultiSelectField(choices=WITH_WHO_CHOICES, default=1)
    accessories = MultiSelectField(choices=ACCESSORIES, null=True, blank=True)
    created = models.DateTimeField(auto_now_add=True, null=False, blank=False)
    scheduled = models.DateTimeField(null=True, blank=True)
    arrived = models.DateTimeField(null=True, blank=True)
    started = models.DateTimeField(null=True, blank=True)
    completed = models.DateTimeField(null=True, blank=True)
    scheduled_end = models.DateTimeField(null=True, blank=True)
    detected_end = models.DateTimeField(null=True, blank=True)
    approved = models.BooleanField(default=False)
    area_start = models.ForeignKey(Area, on_delete=models.CASCADE, null=False, related_name='jobs_start')
    area_end = models.ForeignKey(Area, on_delete=models.CASCADE, null=False, related_name='jobs_end')
    comment = models.CharField(max_length=256, null=True, blank=True)
    worker = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='jobs_worker')

我有此URL可以进行GET,POST,PUT和DELETE。

router.register(r'jobs', views.JobList)

链接到的视图继承自ModelViewSet:

class JobList(LoginRequiredMixin, viewsets.ModelViewSet):
    queryset = Job.objects.all()
    serializer_class = JobsSerializer

据我了解,默认情况下,仅通过从ModelViewSet继承,API即可处理GET,POST和PUT。这可能是为什么在Web API中我看到带有要发送到POST(see this screenshot)的数据的表单。该视图可以完美地处理GET,但是问题出在POST请求上。

如您在screenshot中所见,POST数据仅需填写3个字段。但是在模型中,我有更多声明为null=False的字段,这些字段与POST数据框中的字段不同。因此,一个问题将是:

  • API从何处获取要显示的必填字段的信息?

如果我尝试POST,则会收到此错误: NOT NULL constraint failed: job_manager_job.area_end_id

我在视图和序列化程序中添加了 create()函数,以调试API进程。此时,我手动添加了要创建作业(see this other screenshot)所需的一些字段。如您所见,我在两个相似的键中添加了相同的值,这又引出了另一个问题:

  • JSON需要哪个键?是模型的字段名称还是序列化程序中的字段?

视图如下:

class JobList(LoginRequiredMixin, viewsets.ModelViewSet):

    queryset = Job.objects.all()
    serializer_class = JobsSerializer

    def create(self, request, *args, **kwargs):
        json_data = request.data
        job_serializer = self.serializer_class(data=json_data)
        if job_serializer.is_valid():
            job_serializer.save()
            print("valid data")
        pass

和这样的序列化器:

class JobsSerializer(serializers.ModelSerializer):

    status = serializers.SerializerMethodField('get_status')
    area_from = serializers.StringRelatedField(source='area_start.name', default=None)
    area_to = serializers.StringRelatedField(source='area_end.name', default=None)
    assigned = serializers.SerializerMethodField('get_assigned')
    info = serializers.SerializerMethodField('get_info')

    def create(self, validated_data):
        print(validated_data)
        Job.objects.create(**validated_data)
        pass


    def get_status(self, a_job):
        if a_job.approved:
            return 'Approved'
        if a_job.completed:
            return 'Completed'
        if a_job.started:
            return 'Started'
        if a_job.arrived:
            return 'Arrived'
        if a_job.scheduled:
            return 'Scheduled'
        if a_job.created:
            return 'Created'
        return 'Defined'

    def get_info(self, a_job):
        return get_job_info_options(a_job)

    def get_assigned(self, a_job):
        try:
            a = a_job.worker.first_name + ' ' + a_job.worker.last_name
        except AttributeError:
            a = None
        return a

    class Meta:
        model = Job
        fields = ['pk', 'status', 'scheduled', 'scheduled_end', 'assigned', 'area_from', 'area_to', 'patient', 'info']

问题在于,我在调试器中看到该视图接收了所有JSON数据(包括额外的密钥),这些数据在self.serializer_class(data=json_data)中传递给了序列化程序,但在 validated_data 中序列化程序仅包含POST框中显示的3个键。我不知道此数据如何在序列化程序中消失。 检查this screenshot,以确保序列化程序的data={...} create 函数

中的validated_data不同

不仅会解决此问题,而且如果有人能回答上述有关django内部工作原理的问题,我将非常感激。

谢谢。

1 个答案:

答案 0 :(得分:1)

让我们看看:

fields = [
    'pk',  # unused in create
    'status',  # on serializer, read only method field
    'scheduled',  # OK
    'scheduled_end',  # OK
    'assigned',  # on serializer, read only method field
    'area_from',  # on serializer, read only string related field
    'area_to',  # on serializer, read only string related field
    'patient',  # OK
    'info'  # on serializer, read only method field
]

我得到3个OK,所以我认为DRF是正确的:)

问题:

  • API从何处获取要显示的必填字段的信息?

serializer.Meta.fields中的所有可写字段都以表格形式结束。表单不需要呈现它们。

  • JSON需要哪个键?是模型的字段名称还是序列化程序中的字段?

序列化器的字段名称。但是更准确地说,Parsers are first in the pipeline,它允许您send camelCase json and get snake_case in validated data

最简单的解决方法是PrimaryKeyRelatedField。这意味着消费者需要记住主键,但是SlugRelatedField可以使事情保持可读性。