Para un número de razones^, me gustaría utilizar un UUID como una clave principal en algunos de mis modelos de Django. Si lo hago, ¿voy a ser capaz de utilizar fuera de apps como «contrib.comentarios», «django derecho a voto» o «django-tagging» que el uso genérico de las relaciones a través de ContentType?

El uso de «django derecho a voto» como un ejemplo, el Voto modelo se parece a esto:

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)

Esta aplicación parece estar asumiendo que la clave principal para el modelo de ser votado es un entero.

De la incorporada en los comentarios de la aplicación parece ser capaces de manejar los no-entero PKs, a pesar de que:

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")

Es este «integer-PK-supone» un problema común de la situación para aplicaciones de terceros que haría uso de los Uuid de un dolor? O, posiblemente, estoy malinterpretando esta situación?

Hay una manera de usar Uuid como claves primarias en Django sin causar demasiados problemas?


^ Algunas de las razones: ocultar el objeto cuenta, la prevención de la url «id de rastreo», el uso de múltiples servidores para crear conflicto no objetos, …

InformationsquelleAutor mitchf | 2010-10-14

4 Comentarios

  1. 42

    Un UUID clave principal causa de problemas no sólo con relaciones genéricas, sino con la eficiencia en general: todos los extranjeros clave va a ser mucho más caro, tanto para la tienda, y a unirse en que una palabra de máquina.

    Sin embargo, nada requiere el UUID a ser la clave principal: sólo tienes que hacer un secundaria clave, al complementar el modelo con un uuid de campo con unique=True. El uso implícito de la clave principal como normal (interno de su sistema), y utilizar el UUID como su identificador externo.

    • Además, puede reemplazar save y generar su UUID allí cuando un objeto se guarda en el primer tiempo (por comprobar si el objeto tiene una clave principal).
    • Joe Holloway, no hay necesidad para que: usted puede simplemente suministro de la UUID de la función de generación como el campo de la default.
    • Gracias Piet. Su solución es lo que estoy haciendo ahora y funciona para oscurecer la clave principal en la URI (aunque el comentario de la aplicación muestra que todavía en un campo oculto en el «crear comentarios» del formulario). No me da la ventaja de ser capaz de crear fácilmente no chocar filas de la base de datos en servidores independientes, aunque. Oh, bueno, supongo que voy a aprender a re-encanta el integer clave primaria.
    • Joe: yo uso django_extensions.db.campos.UUIDField para crear mi Uuid en mi modelo. Es simple, me acaba de definir mi campo como este: user_uuid = UUIDField()
    • Uno (molesto) efecto secundario de hacer esto, y teniendo predeterminado=uuid.uuid4 (o equivalente) es que, si usted está utilizando el sur para las migraciones, entonces usted necesita para editar el archivo de migración cada vez que usted tiene una nueva migración, y quitar el valor predeterminado para este campo.
    • Cuando se utiliza django_extensions.db.fields.UUIDField como se ha mencionado por mitchf, usted no tendrá ningún problema con Django-Sur de las migraciones campo – mencionado por él tiene soporte incorporado para el Sur de las migraciones.
    • Terrible respuesta. Postgres tiene nativas (128 bits) Uuid que son sólo 2 palabras en una máquina de 64 bits, así que no sería «mucho más caro» que el nativo de 64 bits INT.
    • postfuturist: PostgreSQL UUID del tipo (en la actualidad, al menos) implementado como un C matriz de char, con comparaciones utilizando memcmp(): esta es, de hecho, va a ser mucho más caro que el de una máquina de comparación de palabras, en general. Además de eso, debe tener en cuenta localidad: si su Uuid son distribuidos de manera uniforme, en lugar de secuencial, su índice de rendimiento puede ir por el desagüe, dependiendo de su carga de trabajo. (Esto es especialmente importante para el índice agrupado los motores, tales como MySQL InnoDB.)
    • Piet, dado que tiene un índice de árbol b en ello, ¿cuántas comparaciones están ahí va a estar en una consulta determinada? No muchos. Además, estoy seguro de que el memcmp llamada será alineado y optimizado en la mayoría de sistemas operativos. Basado en la naturaleza de las preguntas, yo diría que no el uso de UUID debido a la posible (probable insignificante) las diferencias de rendimiento es el mal de optimización.
    • Depende, por supuesto: que la naturaleza de la optimización. Respecto al índice, no es la profundidad del árbol o el número de comparaciones que son importantes, pero la distribución de claves: una distribución aleatoria en esencia se requiere que todas las páginas de ajuste en la memoria de trabajo (y hacer las actualizaciones del índice más costoso), mientras secuencial claves tienden a seguir los datos naturales de la agrupación. Esto puede (o no) tener un enorme impacto en el rendimiento, pero de cualquier manera, es algo a tener en cuenta.
    • Es difícil encontrar buenas referencias acerca de este tema, pero por ejemplo, aquí es un viejo artículo comparando aleatoriamente distribuidos Guid modificado, serializado Guid en MS SQL. Con un punto de referencia que se inserta 500,000 órdenes, el azar Guid tomó alrededor de 30 veces más que el serializado Guid, que tomó aproximadamente el mismo tiempo que las claves principales de enteros. Asimismo, el serializado Guid sólo consumió alrededor de 1MB de memoria por 500 pedidos, mientras que el azar Guid saturado el servidor de prueba es menos 350 mb de memoria para el mismo número de pedidos.
    • Estás general, la generalización. Depende de la base de datos de la aplicación bajo el capó. Y yo conozco una aplicación que comparar la cadena de manera más eficiente que la palabra de máquina.

  2. 181

    Como se ve en la documentación, de Django 1.8 hay una construida en el UUID de campo. Las diferencias de rendimiento cuando se utiliza un UUID vs entero son insignificantes.

    import uuid
    from django.db import models
    
    class MyUUIDModel(models.Model):
        id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

    También puede comprobar esta respuesta para obtener más información.

    • ¿Que resolver el genérico de problemas de las relaciones?
    • ¿cómo podemos establecer django para usar cada vez que al crear automáticamente los Identificadores de las tablas?
    • No muy claro qué es exactamente a qué te refieres con «en cada momento». Si desea Uuid para ser utilizado para cada modelo, crear su propia base abstracta modelo y usarlo en lugar de django.modelos.Modelo.
    • Las diferencias de rendimiento son sólo insignificantes cuando subyacente de la base de datos admite el UUID tipo. Django todavía utiliza un charfield para la mayoría de los DBs (postgresql es el único documentado db para apoyar el UUID de campo).
    • Como se indicó en el Django docs: «primary_key=True implica null=False y unique=True»
  3. 10

    Me encontré en una situación similar y se encontró en el oficial de la documentación de Django, que la object_id no tiene que ser del mismo tipo que el primary_key de los modelos relacionados. Por ejemplo, si desea que su genérico de la relación para que sea válido tanto para IntegerField y CharField id, acaba de establecer su object_id a ser un CharField. Desde enteros puede obligar a las cadenas que estará bien. Lo mismo va para UUIDField.

    Ejemplo:

    class Vote(models.Model):
        user         = models.ForeignKey(User)
        content_type = models.ForeignKey(ContentType)
        object_id    = models.CharField(max_length=50) # <<-- This line was modified 
        object       = generic.GenericForeignKey('content_type', 'object_id')
        vote         = models.SmallIntegerField(choices=SCORES)
  4. -1

    La pregunta puede reformularse como «¿hay una manera de conseguir Django para el uso de un UUID para todos los identificadores de base de datos en todas las tablas en lugar de un incremento automático de número entero?».

    Seguro, que puedo hacer:

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

    en todas mis tablas, pero no puedo encontrar una manera para hacer esto:

    1. La 3ª parte de los módulos de
    2. Django generado ManyToMany tablas

    Así, esto parece ser una falta de Django característica.

Dejar respuesta

Please enter your comment!
Please enter your name here