首页 > 解决方案 > 新的 read_only + drf 3.8 的默认行为给出错误

问题描述

这是错误的示例:

模型:

from django.db import models

class Hero(models.Model):
    alias = models.(max_length=60)
    character = models.ForeignKey(User, on_delete=models.CASCADE)

def __str__(self):
    return self.name

序列化器:

class HeroSerializer(serializers.ModelSerializer):
    character = HyperlinkedRelatedField(read_only=True, default=<some user object>)
    class Meta:
        model = Hero
        fields = ('character', 'alias')

视图集:

class HeroViewSet(NestedViewSetMixin,
                         mixins.CreateModelMixin,
                         mixins.UpdateModelMixin,
                         viewsets.ReadOnlyModelViewSet):
    queryset = Hero.objects.all()
    serializer_class = HeroSerializer

测试:

def test_created_successfully(self):
    alias = 'blab blah'
    response = self.client.post(self.url, {'name': name})
    self.assertEqual(response.status_code, status.HTTP_201_CREATED, response.data)

现在这个过去通过的测试是 drf 3.7.7

当我升级到 drf 3.8.2 这个错误开始发生

django.db.utils.IntegrityError: null value in column "character_id" violates not-null constraint
DETAIL:  Failing row contains (blah_blah, null).

他们说现在 default + read_only 字段已从可写字段中排除,因此您必须通过编写 perform_create 或覆盖序列化程序的 create 、 update 和 save 函数来显式保存这些字段

所以我在视图集中写了这个

def perform_create(self, serializer):
    serializer.save(character=<some user object>)

作为参考,这个 perfrom_create 在 mixins.CreateModelMixin 的 create 方法中被调用

   def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

所以它在这里工作,但现在如果相同的序列化程序更改为(字符字段更改为名称并且名称的来源为“字符字段”。

class HeroSerializer(serializers.ModelSerializer):
    name = HyperlinkedRelatedField(source='character', read_only=True, default=<some user object>)
    class Meta:
        model = Hero
        fields = ('name', 'alias')

我的测试失败了

self.assertEqual(response.status_code, status.HTTP_201_CREATED, response.data)
AssertionError: 400 != 201 : {'character': [ErrorDetail(string='This field is required.', 
code='required')]}

并且这个测试在创建函数的下面行失败,即这甚至没有达到我重写的 perform_create。

serializer.is_valid(raise_exception=True)

数据无效。

需要帮忙。

标签: pythondjangoapidjango-rest-frameworkdjango-serializer

解决方案


推荐阅读