Python 中 x00 和空字符串的区别,以及在 Django 中的坑

事情是这样的,我有一个守护进程,不停地从 RabbitMQ 消费数据,然后保存到 MySQL。操作数据库使用的是 Django 的 ORM 语法。

create

仔细分析了代码之后,感觉可能发生问题的只有这一句:

serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializeris_valid

通过单步调试,走到函数的调用关系中,发现了问题的关键所在。

# django/forms/fields.py

class CharField(Field):
    def __init__(self, *, max_length=None, min_length=None, strip=True, empty_value='', **kwargs):
        self.max_length = max_length
        self.min_length = min_length
        self.strip = strip
        self.empty_value = empty_value
        super().__init__(**kwargs)
        if min_length is not None:
            self.validators.append(validators.MinLengthValidator(int(min_length)))
        if max_length is not None:
            self.validators.append(validators.MaxLengthValidator(int(max_length)))
        self.validators.append(validators.ProhibitNullCharactersValidator())
        ...
CharField
# django/core/validators.py

@deconstructible
class ProhibitNullCharactersValidator:
    """Validate that the string doesn't contain the null character."""
    message = _('Null characters are not allowed.')
    code = 'null_characters_not_allowed'

    def __init__(self, message=None, code=None):
        if message is not None:
            self.message = message
        if code is not None:
            self.code = code

    def __call__(self, value):
        if 'x00' in str(value):
            raise ValidationError(self.message, code=self.code)

    def __eq__(self, other):
        return (
            isinstance(other, self.__class__) and
            self.message == other.message and
            self.code == other.code
        )
__call__x00
x00
x00
x00
>>> a = 'x00'
>>> b = ''
>>>
>>> print(a)

>>> print(b)

>>> a == b
False
>>>
>>> len(a)
1
>>> len(b)
0
>>> print('hellox00world')
helloworld
>>> a = 'hellox00world'
>>> if 'x00' in a:
...     print('111')
...
111
>>>

以上。