从有效负载创建时 Django Rest Framework Not Null 错误
Django Rest Framework Not Null Error when creating from payload
我正在尝试编写一个测试来检查我的 Viewset
的创建方法是否正常工作:
@pytest.mark.django_db
def test_create(admin_user):
parent = factories.ParentFactory()
payload = {
'name': 'child',
'parent_id': parent.pk,
}
view = views.ParentViewSet.as_view({'post': 'create'})
request = factory.post('/', payload, format='json')
force_authenticate(request, user=admin_user)
response = view(request)
assert response.status_code == status.HTTP_201_CREATED
assert models.Child.objects.count() == 1
child = models.Child.objects.first()
assert child.name == 'child'
但是,当我 运行 代码时出现以下错误:
psycopg2.errors.NotNullViolation: null value in column "parent_id" violates not-null constraint
但是 Parent
创建方法的测试 运行 没问题:
def test_create(admin_user):
payload = {
'name': 'parent',
'children': [
{
'name': 'child',
}
],
}
view = views.ParentViewSet.as_view({'post': 'create'})
request = factory.post('/', payload, format='json')
force_authenticate(request, user=admin_user)
response = view(request)
assert response.status_code == status.HTTP_201_CREATED
assert models.Parent.objects.count() == 1
season = models.Parent.objects.first()
assert season.name == 'parent'
assert season.children.count() == 1
有人可以告诉我为子测试创建编写有效负载的正确方法吗?
编辑:
serializers.py
class ChildSerializer(serializers.ModelSerializer):
class Meta:
model = models.Child
fields = ['id', 'name']
class ParentSerializer(serializers.ModelSerializer):
children = ChildSerializer(many=True)
class Meta:
model = models.Parent
fields = ['id', 'name', 'children']
def create(self, validated_data):
children = validated_data.pop('children')
parent = super().create(validated_data)
for child in children:
child['parent'] = parent
self.fields['children'].create(children)
return parent
views.py
class ParentViewSet(
viewsets.GenericViewSet,
mixins.CreateModelMixin,
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
mixins.DestroyModelMixin,
):
queryset = models.Parent.objects.all().prefetch_related(
'children'
)
serializer_class = serializers.ParentSerializer
class ChildViewSet(
viewsets.GenericViewSet,
mixins.CreateModelMixin,
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
mixins.DestroyModelMixin,
):
queryset = models.Child.objects.all().prefetch_related(
'children'
)
serializer_class = serializers.ChildSerializer
我认为您在子模型中有一个字段 "parent",但是因为您没有在 ChildSerializer 中包含该字段,即使您在请求中发送它也是如此body,它在创建 Child 实例时不包含在内,因此会出现错误。你有几种方法可以解决它
1 - 您可以将父字段添加到 ChildSerializer:
class ChildSerializer(serializers.ModelSerializer):
class Meta:
model = models.Child
fields = ['id', 'name', 'parent']
并像这样发送请求:
payload = {
'name': 'child',
'parent': parent.pk,
}
2 - 如果你不想这样,你可以保持 ChildSerializer 现在的样子,并且只在保存子实例时添加父实例,像这样:
class ChildViewSet(
...
):
queryset = models.Child.objects.all().prefetch_related('children')
serializer_class = serializers.ChildSerializer
def perform_create(self, serializer):
serializer.save(parent_id=self.request.data.get('parent'))
同样,您需要像这样发送请求:
payload = {
'name': 'child',
'parent': parent.pk,
}
但是在第二种情况下,您没有在请求验证中包括父字段,如果客户端没有发送父字段或在那里发送无效值,您将得到一个异常。如果您要使用此解决方案,我建议您也以某种方式验证父字段。
我正在尝试编写一个测试来检查我的 Viewset
的创建方法是否正常工作:
@pytest.mark.django_db
def test_create(admin_user):
parent = factories.ParentFactory()
payload = {
'name': 'child',
'parent_id': parent.pk,
}
view = views.ParentViewSet.as_view({'post': 'create'})
request = factory.post('/', payload, format='json')
force_authenticate(request, user=admin_user)
response = view(request)
assert response.status_code == status.HTTP_201_CREATED
assert models.Child.objects.count() == 1
child = models.Child.objects.first()
assert child.name == 'child'
但是,当我 运行 代码时出现以下错误:
psycopg2.errors.NotNullViolation: null value in column "parent_id" violates not-null constraint
但是 Parent
创建方法的测试 运行 没问题:
def test_create(admin_user):
payload = {
'name': 'parent',
'children': [
{
'name': 'child',
}
],
}
view = views.ParentViewSet.as_view({'post': 'create'})
request = factory.post('/', payload, format='json')
force_authenticate(request, user=admin_user)
response = view(request)
assert response.status_code == status.HTTP_201_CREATED
assert models.Parent.objects.count() == 1
season = models.Parent.objects.first()
assert season.name == 'parent'
assert season.children.count() == 1
有人可以告诉我为子测试创建编写有效负载的正确方法吗?
编辑:
serializers.py
class ChildSerializer(serializers.ModelSerializer):
class Meta:
model = models.Child
fields = ['id', 'name']
class ParentSerializer(serializers.ModelSerializer):
children = ChildSerializer(many=True)
class Meta:
model = models.Parent
fields = ['id', 'name', 'children']
def create(self, validated_data):
children = validated_data.pop('children')
parent = super().create(validated_data)
for child in children:
child['parent'] = parent
self.fields['children'].create(children)
return parent
views.py
class ParentViewSet(
viewsets.GenericViewSet,
mixins.CreateModelMixin,
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
mixins.DestroyModelMixin,
):
queryset = models.Parent.objects.all().prefetch_related(
'children'
)
serializer_class = serializers.ParentSerializer
class ChildViewSet(
viewsets.GenericViewSet,
mixins.CreateModelMixin,
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
mixins.DestroyModelMixin,
):
queryset = models.Child.objects.all().prefetch_related(
'children'
)
serializer_class = serializers.ChildSerializer
我认为您在子模型中有一个字段 "parent",但是因为您没有在 ChildSerializer 中包含该字段,即使您在请求中发送它也是如此body,它在创建 Child 实例时不包含在内,因此会出现错误。你有几种方法可以解决它
1 - 您可以将父字段添加到 ChildSerializer:
class ChildSerializer(serializers.ModelSerializer):
class Meta:
model = models.Child
fields = ['id', 'name', 'parent']
并像这样发送请求:
payload = {
'name': 'child',
'parent': parent.pk,
}
2 - 如果你不想这样,你可以保持 ChildSerializer 现在的样子,并且只在保存子实例时添加父实例,像这样:
class ChildViewSet(
...
):
queryset = models.Child.objects.all().prefetch_related('children')
serializer_class = serializers.ChildSerializer
def perform_create(self, serializer):
serializer.save(parent_id=self.request.data.get('parent'))
同样,您需要像这样发送请求:
payload = {
'name': 'child',
'parent': parent.pk,
}
但是在第二种情况下,您没有在请求验证中包括父字段,如果客户端没有发送父字段或在那里发送无效值,您将得到一个异常。如果您要使用此解决方案,我建议您也以某种方式验证父字段。