Django Rest Framework说非必需字段为必填项

时间:2018-10-30 15:11:57

标签: python django

背景故事

在Django中,我有模型

class Company(models.Model):
    name = models.TextField(null=False,unique=True)
    date_added = models.DateTimeField(auto_now_add=True)

class Address(models.Model):
    street = models.TextField()

class Person(models.Model ): 
    firstname = models.TextField()
    address = models.ForeignKey(Address,null= True,on_delete=models.SET_NULL)
    company = models.ForeignKey(Company,null=True,on_delete=models.SET_NULL)

每个人都有一个地址和一家公司。(均为非必填字段)

在DRF中,我有序列化器。

class AddressSerializer(serializers.ModelSerializer):
    class Meta:
        model = Address
        fields = '__all__'

class CompanySerializer(serializers.ModelSerializer):

    class Meta:
        model = Company
        fields = "__all__"

class PersonSerializer(serializers.ModelSerializer):

    class Meta:
        model = Person
        fields = ('id', 'firstname',  'address','company')

    def to_representation(self, instance):
        response = super().to_representation(instance)
        response['address'] = AddressSerializer(instance.address).data
        response['company'] = CompanySerializer(instance.company).data
        return response

和视图集

class PersonViewSet(viewsets.ModelViewSet,UpdateModelMixin):
    queryset = Person.objects.all()
    serializer_class = PersonSerializer
    filter_backends = (OrderingFilter,DjangoFilterBackend,SearchFilter)
    filter_fields = ('id','company','firstname','middlename','lastname',)
    search_fields = ('firstname','middlename','lastname',)

class CompanyViewSet(viewsets.ModelViewSet,UpdateModelMixin):
    queryset = Company.objects.all()
    serializer_class = CompanySerializer
    filter_backends = (OrderingFilter,DjangoFilterBackend,SearchFilter)
    filter_fields = ('id','name',)
    search_fields = ('name',)

class AddressViewSet(viewsets.ModelViewSet,UpdateModelMixin):
    queryset = Address.objects.all()
    serializer_class = AddressSerializer
    filter_backends = [DjangoFilterBackend]
    filter_fields = ['id','street']

问题

将数据{"firstname":"foo"}发送到此序列化程序时,它将返回400错误代码。 {"company": ["This field is required."]}

奇怪的是,地址字段的设置似乎与公司字段完全相同,但不会引发此错误。

为使此工作有效,必须将{"firstname":"foo","company":null}发布到序列化程序,考虑到address字段工作正常,这看起来有点愚蠢。

有人知道导致这个问题的原因是什么,以及如何防止这种情况发生吗?

3 个答案:

答案 0 :(得分:3)

在您的ForeignKey构造函数中,除了blank=True之外,还需要包括null=True

address = models.ForeignKey(Address,blank=True,null=True,on_delete=models.SET_NULL)
company = models.ForeignKey(Company,blank=True,null=True,on_delete=models.SET_NULL)

答案 1 :(得分:0)

不确定,但是尝试将其更改为此

fields = ('id', 'firstname',  'address','company',)

答案 2 :(得分:0)

我完全模拟了您所写的内容,但没有发现问题中所发布的问题。没有引发任何错误。

#My Models

class Company(models.Model):
    name = models.TextField(null=False,unique=True)
    date_added = models.DateTimeField(auto_now_add=True)

class Address(models.Model):
    street = models.TextField()

class Person(models.Model ):
    firstname = models.TextField()
    address = models.ForeignKey(Address,null= True,on_delete=models.SET_NULL)
    company = models.ForeignKey(Company,null=True,on_delete=models.SET_NULL)

#My Viewset

class PersonViewSet(viewsets.ModelViewSet, UpdateModelMixin):
    queryset = Person.objects.all()
    serializer_class = PersonSerializer
    filter_backends = (OrderingFilter, DjangoFilterBackend, SearchFilter)
    filter_fields = ('id', 'company', 'firstname', 'middlename', 'lastname',)
    search_fields = ('firstname', 'middlename', 'lastname',)


class CompanyViewSet(viewsets.ModelViewSet, UpdateModelMixin):
    queryset = Company.objects.all()
    serializer_class = CompanySerializer
    filter_backends = (OrderingFilter, DjangoFilterBackend, SearchFilter)
    filter_fields = ('id', 'name',)
    search_fields = ('name',)


class AddressViewSet(viewsets.ModelViewSet, UpdateModelMixin):
    queryset = Address.objects.all()
    serializer_class = AddressSerializer
    filter_backends = [DjangoFilterBackend]
    filter_fields = ['id', 'street']

#My Serializer

class AddressSerializer(serializers.ModelSerializer):
    class Meta:
        model = Address
        fields = '__all__'

class CompanySerializer(serializers.ModelSerializer):

    class Meta:
        model = Company
        fields = "__all__"

class PersonSerializer(serializers.ModelSerializer):

    class Meta:
        model = Person
        fields = ('id', 'firstname',  'address','company')

    def to_representation(self, instance):
        response = super().to_representation(instance)
        response['address'] = AddressSerializer(instance.address).data
        response['company'] = CompanySerializer(instance.company).data
        return response

#My tests
class PersonTests(APITestCase):

    def test_create_person(self):
        url = reverse('person-list')
        data = {"firstname": "foo"}
        response = self.client.post(url, data, format='json')
        print(response.content)
        self.assertEqual(response.status_code, HTTP_201_CREATED)

Test Results: