我有一个Django项目,我最近从Django 2.2升级到了3.2。在这个项目中,我使用了一个自定义的UUIDField
,它将UUID保存为char(36)
,格式如下:12345678-1234-5678-1234-567812345678
。
import uuid
from django.db import models
class UUIDField(models.UUIDField):
"""
Overrides Django UUIDField to store full UUID's including dashes.
"""
def __init__(self, verbose_name=None, **kwargs):
super().__init__(verbose_name, **kwargs)
self.max_length = 36
def get_internal_type(self):
return "CharField"
def get_db_prep_value(self, value, connection, prepared=False):
if value is None:
return None
if not isinstance(value, uuid.UUID):
try:
value = uuid.UUID(value)
except AttributeError:
raise TypeError(self.error_messages['invalid'] % {'value': value})
if connection.features.has_native_uuid_field:
return value
return str(value)
升级后,我注意到搜索完整的UUID不再起作用。如果我只提供UUID的第一部分(直到第一个连字符后的第一个字符),它会像预期的那样工作。
Python 3.6.9 (default, Mar 15 2022, 13:55:28)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from foobar.foo.models import Foo
>>>
>>> Foo.objects.all()
<QuerySet [<Foo: Foo object (34c46fe8-caf0-11ec-bdb9-482ae362a4c0)>]>
>>>
>>> Foo.objects.filter(id__icontains='34c46fe8-caf0-11ec-bdb9-482ae362a4c0')
<QuerySet []>
>>>
>>> Foo.objects.filter(id__icontains='34c46fe8-')
<QuerySet [<Foo: Foo object (34c46fe8-caf0-11ec-bdb9-482ae362a4c0)>]>
>>>
>>> Foo.objects.filter(id__icontains='34c46fe8-c')
<QuerySet []>
>>>
我已经尝试过UUIDField
方法,但我似乎找不出哪里出错了。这里有一个链接,指向一个使用简化模型的Gist,我从那里得到了上面的shell示例。
2条答案
按热度按时间s3fp2yjn1#
经过长时间的
pdb
调试,我终于找到了问题所在。我希望在调试过程中找到原始的SQL片段,但一个名为WhereNode
的对象引起了我的注意。我注意到这一行:
我不知道
django.db.models.lookups.UUIDIContains
对象是什么,所以直接去Django的源代码找答案。这是一个空类,由两个mixinIContains
和UUIDTextMixin
组成。在我的例子中,后者是罪魁祸首,因为它从查找值中删除了所有连字符。这是2.2版之后的introduced as a fix,我在升级之前使用的,为了支持没有本地UUID类型的数据库后端(例如,在我的情况下,MySQL 5.7)。修复非常简单,我只需要注册一个自定义的
UUIDIContains
类,而不需要为我的自定义UUIDField
注册UUIDTextMixin
。我的新
fields.py
:ruyhziif2#
米洛得到了答案,但在我的情况下,我也不得不这样做iexact查找。我使用MSSQL原生uuid,通过自定义UUID字段,因为没有后端支持原生版本。但MSSQL不支持无dash版本的uuid。
我的UUIDField略有不同,但我还必须添加注册IExact查找,而不使用UUIDTextMixin。