UUIDField vs Charfield с UUID в нем?
Итак, я использую UUID в поле CharField в качестве PK для многих вещей в проекте, над которым я работаю, все работает нормально, никаких проблем. Если я использую UUIDField, некоторые вещи в бэкенде будут иметь проблемы с UUID-полем (обычно это функции, которые ожидают, что UUID будет строкой).
Есть ли преимущество использования UUIDField по сравнению с просто 'default=uuid.uuid4' в CharField?
UUIDField
- это, по сути, поле CharField длиной 32 символа, которое проверяет, что был предоставлен действительный UUID. Согласно документации, тип UUID будет сохранен в Postgres, но как CharField в любой другой БД.
https://docs.djangoproject.com/en/4.0/ref/models/fields/#uuidfield
Не понимаю, почему вы не можете просто использовать CharField с default=uuid.uuid4
(который в любом случае нужен для UUIDField), вы просто потеряете автоматическую валидацию.
Есть ли преимущество использования UUIDField по сравнению с просто
default=uuid.uuid4
вCharField
?
Да.
A UUIDField
для базы данных postgresql будет использоваться UUID
типа [postgresql-doc], это сохранит UUID в виде 128-битного количества, что более компактно, чем хранение в виде строки, для которой потребуется 32 байта или, соответственно, 256 бит (что занимает в два раза больше места).
Если вы будете использовать CharField(max_length=36, default=uuid.uuid4)
, вам даже потребуется использовать 36 символов, так как UUID
по умолчанию для str
добавляет тире между ними, а не только использует шестнадцатеричное значение, и таким образом добавляет дополнительные четыре символа для этих тире, которые по сути одинаковы, и таким образом тратит больше памяти.
Но кроме этого есть и другие преимущества. Действительно, он будет следить за тем, чтобы длина CharField
составляла 32 символа, и что формат, если он передан как строка, действительно является UUID. Таким образом, он будет выполнять надлежащую проверку формата.
Он также может разобрать несколько форматов строки в один и тот же UUID
. Например, {12345678-1234-5678-1234-567812345678}
, 12345678123456781234567812345678
и urn:uuid:12345678-1234-5678-1234-567812345678
будут разобраны в одно и то же значение, этого не произойдет, если вы используете простое CharField
, так как тогда он будет считать, что это разные строки. Если вы, таким образом, работаете с:
MyModel.objects.filter(pk='urn:uuid:12345678-1234-5678-1234-567812345678')
Он получит запись с этим UUID, даже если значение хранится в базе данных в другом формате.
Значения, которые он извлекает из базы данных, обернуты в тип UUID
. Это "богаче", чем str
инг, и позволит избежать ошибок. Например, добавление двух UUID
не имеет смысла. Действительно:
>>> uuid4() + uuid4()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'UUID' and 'UUID'
тогда как для строк это приведет к конкатенации двух строк.
Кроме того, он работает с UUIDField
[Django-doc] как поле формы, это делает более удобным подключить другой виджет к этому типу поля, и таким образом отрисовать форму по-другому.
Таким образом, он предоставляет больше контекста о том, какой тип данных он ожидает, и обычно лучший контекст означает, что модули, которые интроспектируют модель, могут, таким образом, сделать лучшую работу.