Por vários motivos ^, gostaria de usar um UUID como chave primária em alguns dos meus modelos Django. Se eu fizer isso, ainda poderei usar aplicativos externos como "contrib.comments", "django-votes" ou "django-tagging", que usam relações genéricas via ContentType?
Usando "django-vote" como exemplo, o modelo Vote se parece com isto:
class Vote(models.Model):
user = models.ForeignKey(User)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
object = generic.GenericForeignKey('content_type', 'object_id')
vote = models.SmallIntegerField(choices=SCORES)
Este aplicativo parece estar assumindo que a chave primária para o modelo que está sendo votado é um número inteiro.
O aplicativo de comentários integrado parece ser capaz de lidar com PKs não inteiros, embora:
class BaseCommentAbstractModel(models.Model):
content_type = models.ForeignKey(ContentType,
verbose_name=_('content type'),
related_name="content_type_set_for_%(class)s")
object_pk = models.TextField(_('object ID'))
content_object = generic.GenericForeignKey(ct_field="content_type", fk_field="object_pk")
É este problema "assumido por PK inteira" uma situação comum para aplicativos de terceiros que tornaria o uso de UUIDs uma dor? Ou, possivelmente, estou interpretando mal esta situação?
Existe uma maneira de usar UUIDs como chaves primárias no Django sem causar muitos problemas?
^ Algumas das razões: ocultar contagens de objetos, evitar "rastreamento de id" de url, usar vários servidores para criar objetos não conflitantes, ...
default
.django_extensions.db.fields.UUIDField
conforme mencionado por mitchf, você não terá problemas com as migrações Django-South - o campo mencionado por ele tem suporte embutido para migrações South.Como visto na documentação , no Django 1.8 existe um campo UUID embutido. As diferenças de desempenho ao usar um UUID vs inteiro são insignificantes.
Você também pode verificar esta resposta para obter mais informações.
fonte
Eu me deparei com uma situação semelhante e descobri na documentação oficial do Django , que o
object_id
não precisa ser do mesmo tipo que o primary_key do modelo relacionado. Por exemplo, se você deseja que seu relacionamento genérico seja válido para os IDs de IntegerField e CharField , apenas defina seuobject_id
como CharField . Uma vez que inteiros podem coagir em strings, tudo bem. O mesmo vale para UUIDField .Exemplo:
fonte
O verdadeiro problema do UUID como PK é a fragmentação do disco e a degradação da inserção associada a identificadores não numéricos. Como o PK é um índice agrupado, quando não é incrementado automaticamente, seu mecanismo de banco de dados terá que recorrer ao seu drive físico ao inserir uma linha com um id de ordinalidade inferior, o que acontecerá o tempo todo com UUIDs. Quando você obtém muitos dados em seu banco de dados, pode levar vários segundos ou até minutos apenas para inserir um novo registro. E seu disco eventualmente ficará fragmentado, exigindo desfragmentação periódica do disco. Isso tudo é muito ruim.
Para resolver isso, recentemente criei a seguinte arquitetura que achei que valeria a pena compartilhar.
O UUID Pseudo-Chave Primária
Este método permite que você aproveite os benefícios de um UUID como uma chave primária (usando um UUID de índice exclusivo), enquanto mantém um PK incrementado automaticamente para lidar com a fragmentação e inserir questões de degradação de desempenho de ter um PK não numérico.
Como funciona:
pkid
em seus modelos de banco de dados.id
campo para permitir que você pesquise por um ID de UUID, em vez de uma chave primária numérica.to_field='id'
) para permitir que suas chaves estrangeiras representem adequadamente o Pseudo-PK em vez da ID numérica.Essencialmente, você fará o seguinte:
Primeiro, crie um Django Base Model abstrato
Certifique-se de estender o modelo básico em vez de models.Model
Além disso, certifique-se de que suas Chaves estrangeiras apontem para o
id
campo UUID em vez dopkid
campo incrementado automaticamente :Se você estiver usando Django Rest Framework (DRF), certifique-se de criar também uma classe Base ViewSet para definir o campo de pesquisa padrão:
E estenda isso em vez do ModelViewSet básico para suas visualizações de API:
Mais notas sobre o porquê e como neste artigo: https://www.stevenmoseley.com/blog/uuid-primary-keys-django-rest-framework-2-steps
fonte
isso pode ser feito usando um modelo abstrato base personalizado, usando as etapas a seguir.
Primeiro crie uma pasta em seu projeto, chame-a de basemodel e, em seguida, adicione um abstractmodelbase.py com o seguinte:
segundo: em todo o seu arquivo de modelo para cada aplicativo, faça isso
Portanto, o incidente do modelo acima é inerente a todo o campo do modelo básico.
fonte
A questão pode ser reformulada como "existe uma maneira de fazer o Django usar um UUID para todos os ids de banco de dados em todas as tabelas ao invés de um inteiro auto-incrementado?".
Claro, eu posso fazer:
em todas as minhas tabelas, mas não consigo encontrar uma maneira de fazer isso por:
Portanto, este parece ser um recurso ausente do Django.
fonte