2010-04-20 29 views
21

Actualmente estoy construyendo un proyecto que involucra mucha inteligencia colectiva. Cada usuario que visita el sitio web se crea un perfil único y sus datos se utilizan luego para calcular las mejores coincidencias para ellos y otros usuarios.Django BigInteger autoincremento de campo como clave principal?

De forma predeterminada, Django crea un campo INT (11) id para manejar las claves primarias de los modelos. Me preocupa que esto se desborde muy rápidamente (es decir, ~ 2.4b dispositivos que visitan la página sin configuración previa de cookies). ¿Cómo puedo cambiarlo para que se represente como BIGINT en MySQL y long() dentro de Django?

he encontrado lo que podía hacer lo siguiente (http://docs.djangoproject.com/en/dev/ref/models/fields/#bigintegerfield):

class MyProfile(models.Model): 
    id = BigIntegerField(primary_key=True) 

Pero hay una manera para que sea incrementado automáticamente, como de costumbre id campos? Además, ¿puedo hacerlo sin firmar para que tenga más espacio para completar?

Gracias!

Respuesta

6

Puede cambiar la tabla posteriormente. Esa puede ser una mejor solución.

1

También tuve el mismo problema. Parece que no hay soporte para los campos automáticos BigInteger en django.

He intentado crear un campo personalizado BigIntegerAutoField pero tuve un problema con el sistema de migración al sur (South no pudo crear una secuencia para mi campo).

Después de dar un par intento de los diferentes enfoques que decidí seguir el consejo de Mateo y alteran la tabla (por ejemplo ALTER TABLE table_name ALTER COLUMN id TYPE bigint; en PostgreSQL)

sería bueno tener solución con el apoyo de Django (como construida en BigIntegerAutoField) y el sur.

+0

creo que esto no ayudaría, como Django todavía poner de identificación en int normal, que todavía es demasiado pequeño. – letoosh

+0

No, en absoluto, el punto aquí es cómo se almacena id en la base de datos. (Largo) tipo entero en python tiene una precisión "ilimitada". También puede comprobar cómo se implementa BigIntegerField en Django 1.2 - hereda directamente IntegreField, sin cambiar el tipo interno para almacenar el valor (que es int en este caso) – dzida

+0

Tiene razón, mi mal ... – letoosh

13

NOTA: Esta respuesta se modificó según el código de Larry. Solución hasta ahora extendida fields.BigIntegerField, pero mejor extender fields.AutoField

que tenía el mismo problema y resuelto con la siguiente código:

from django.db.models import fields 
from south.modelsinspector import add_introspection_rules 

class BigAutoField(fields.AutoField): 
    def db_type(self, connection): 
     if 'mysql' in connection.__class__.__module__: 
      return 'bigint AUTO_INCREMENT' 
     return super(BigAutoField, self).db_type(connection) 

add_introspection_rules([], ["^MYAPP\.fields\.BigAutoField"]) 

Al parecer, este está trabajando muy bien con las migraciones al sur.

+2

He votado negativamente esta respuesta porque utilicé esta solución en producción y causó un error de producción. El problema es que debido a que este campo no extiende AutoField, Django no buscará el ID del DB después de escribir un nuevo modelo. Esta es una diferencia en el comportamiento de los campos típicos de incremento automático de ID. Voy a proponer una solución diferente a continuación. Estoy tomando prestado el 99.9% de esta solución, pero no quiero que otros cometan el mismo error. – Larry

+0

¡Tks! Ojalá pudiera recordar dónde necesito esto antes :-). – lfagundes

+2

¿Qué pasa si se usa PostgreSQL? Tal vez podríamos agregar otra condición en esta respuesta: 'elif 'postgres' en conexión .__ clase __.__ módulo__: return 'bigserial'' – Pawamoy

3

Como se indicó anteriormente, podría modificar la tabla posteriormente. Esa es una buena solución.

Para hacer eso sin olvidar, puede crear un módulo de gestión en su paquete de aplicación y usar la señal post_syncdb.

https://docs.djangoproject.com/en/dev/ref/signals/#post-syncdb

Esto puede causar rubor django-admin.py falle. Pero sigue siendo la mejor alternativa que conozco.

16

Inspirado por lfagundes pero con una pequeña pero importante corrección:

class BigAutoField(fields.AutoField): 
    def db_type(self, connection): # pylint: disable=W0621 
     if 'mysql' in connection.__class__.__module__: 
      return 'bigint AUTO_INCREMENT' 
     return super(BigAutoField, self).db_type(connection) 

add_introspection_rules([], [r"^a\.b\.c\.BigAutoField"]) 

Aviso en lugar de extender BigIntegerField, les extiendo AutoField. Esta es una distinción importante. Con AutoField, Django recuperará el ID AUTO INCREMENTADO de la base de datos, mientras que BigInteger no lo hará.

Una preocupación al cambiar de BigIntegerField a AutoField fue la conversión de los datos a un int en AutoField.

Aviso de AutoField de Django:

def to_python(self, value): 
    if value is None: 
     return value 
    try: 
     return int(value) 
    except (TypeError, ValueError): 
     msg = self.error_messages['invalid'] % str(value) 
     raise exceptions.ValidationError(msg) 

y

def get_prep_value(self, value): 
    if value is None: 
     return None 
    return int(value) 

Resulta que esto está bien, como se verifica en una cáscara de pitón:

>>> l2 = 99999999999999999999999999999 
>>> type(l2) 
<type 'long'> 
>>> int(l2) 
99999999999999999999999999999L 
>>> type(l2) 
<type 'long'> 
>>> type(int(l2)) 
<type 'long'> 

En otras palabras, de fundición a un int no truncará el número, ni cambiará el tipo subyacente.

+0

Encontré que también necesitaba una BigForeignKey para hacer Asegúrese de que los tipos fk también estén configurados en bigint. – shangxiao

+0

La pregunta de "OK" con respecto a las llamadas a int() en la declaración de la clase AutoField depende del sistema. Si está en un sistema de 64 bits, entonces sys.maxint devolverá el valor correcto y usted está bien. Si por alguna razón en 2015 usted está en un sistema de 32 bits, bueno, entonces Bigint no funcionaría en postgres de todos modos. :-) –

Cuestiones relacionadas