Django:仅在从浏览器发布时引发验证错误,但未从测试用例

时间:2016-02-23 04:09:24

标签: python django django-rest-framework

我正在使用DRF编写密文加密/解密API,我遇到了一个奇怪的问题。我已经定义了我的一个模型:

class Key(models.Model):
    owner = models.ForeignKey(User, related_name='keys')
    content = models.CharField(max_length=50)
    name = models.CharField(max_length=100, blank=True, default='')
    created = models.DateTimeField(auto_now_add=True)
    alphabet = models.TextField(default=string.ascii_lowercase+string.digits)

此模型的序列化程序(我省略了一些与问题无关的方法):

class KeySerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = Key
        fields = ('url', 'id', 'alphabet', 'content', 'name')

    def validate(self, attrs):
        alphabet = attrs.get('alphabet')
        if alphabet and len(alphabet) > len(set(alphabet)):
            raise ValidationError({'alphabet': 'This field should not contain repeated characters.'})
        alphabet = alphabet or Key._meta.get_field('alphabet').default
        if not all(map(lambda x: x in alphabet, attrs.get('content'))):
            raise ValidationError({'content': 'Invalid characters were provided.'})
        data = dict()
        if 'name' in attrs:
            data['name'] = attrs['name']
        if 'alphabet' in attrs:
            data['alphabet'] = attrs['alphabet']
        if 'content' in attrs:
            data['content'] = attrs['content']

        return data

最后,发布和列出Key的视图:

class KeyList(generics.ListCreateAPIView):
    permission_classes = (IsAuthenticated,)
    serializer_class = KeySerializer

    def get_queryset(self):
        return Key.objects.filter(owner=self.request.user)

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)

我遇到的问题是,当我尝试通过浏览器发布密钥时,使用alphabet属性的空字符串,如下所示:

{ 
    "alphabet": ""
    "content": "foobar"
}

我收到以下回复:

{ 
    "alphabet": ['This field may not be blank.']
}

当然,这是理想的行为。 然而,当我从测试用例或shell发布相同的东西时,我得到了这个:

$ python manage.py shell
Python 2.7.11 (default, Dec  5 2015, 14:44:53)
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.1.76)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.test import Client
>>> from django.core.urlresolvers import reverse
>>>
>>> client = Client()
>>> client.login(username='password', password='username')
True
>>>
>>> response = client.post(reverse('key-list'), data={'alphabet': '', 'content':'guacamole'})
>>> response.data
{'name': u'', 'url': u'http://testserver/myapp/keys/8/', 'alphabet': u'abcdefghijklmnopqrstuvwxyz0123456789', 'content': u'guacamole', 'id': 1}

也就是说,当我从测试用例或shell发布时,不会引发验证错误。为什么会这样?

我还应该注意,当我尝试为content属性发布空字符串时,不会发生同样的问题。这让我怀疑它与alphabetTextField有关,但我不知道如何解释原因。

1 个答案:

答案 0 :(得分:0)

字母表字段具有默认值,因此当您直接通过模型保存时,模型会接受空白并将其替换为默认值。当您使用shell时,触发模型验证

使用浏览器,您会触发另一个需要字段的验证,然后失败。

错误是这样的:

alphabet = alphabet or Key._meta.get_field('alphabet').default

它没有像模型那样返回正确的默认值。