2010-04-20 5 views
21

Je suis en train de construire un projet qui implique beaucoup d'intelligence collective. Chaque utilisateur visitant le site Web obtient un profil unique et leurs données sont ensuite utilisées pour calculer les meilleurs résultats pour eux-mêmes et pour les autres utilisateurs. Par défaut, Django crée un champ INT (11) id pour gérer les clés primaires des modèles. Je suis préoccupé par ce survol très rapidement (c'est-à-dire ~ 2.4b périphériques visitant la page sans cookie préalable mis en place). Comment puis-je le changer pour être représenté comme BIGINT dans MySQL et long() dans Django lui-même?Champ Django BigInteger à incrémentation automatique en tant que clé primaire?

que j'ai trouvé que je pouvais faire ce qui suit (http://docs.djangoproject.com/en/dev/ref/models/fields/#bigintegerfield):

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

Mais est-il un moyen de le rendre auto-incrémentation, comme les champs habituels id? De plus, puis-je le rendre non signé afin d'avoir plus d'espace à remplir?

Merci!

Répondre

6

Vous pourriez modifier la table par la suite. C'est peut-être une meilleure solution.

1

J'ai également eu le même problème. On dirait qu'il n'y a pas de support pour les champs auto BigInteger dans django.

J'ai essayé de créer un champ personnalisé BigIntegerAutoField mais j'ai rencontré un problème avec le système de migration sud (sud ne pouvait pas créer de séquence pour mon champ).

Après avoir donné un couple essayer différentes approches j'ai décidé de suivre les conseils de Matthieu et faire modifier la table (par exemple ALTER TABLE table_name ALTER COLUMN id TYPE bigint; dans postgre)

serait génial d'avoir une solution soutenue par django (comme construit BigIntegerAutoField) et au sud.

+0

Je pense que ce ne serait pas utile, comme Django serait encore mis ids en int normal, ce qui est encore trop faible. – letoosh

+0

Pas du tout, le point ici est comment id est stocké sur la base de données. Le type entier (long) en python a une précision 'illimitée'. Vous pouvez également vérifier comment BigIntegerField est implanté dans Django 1.2 - il hérite directement d'IntegreField, sans changer de type interne pour stocker la valeur (qui est int dans ce cas) – dzida

+0

Vous avez raison, mon mauvais ... – letoosh

13

NOTE: Cette réponse a été modifiée, selon le code de Larry. solution précédente fields.BigIntegerField étendue, mais il vaut mieux étendre fields.AutoField

J'ai eu le même problème et résolu avec le code suivant:

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

Apparemment, cela fonctionne très bien avec les migrations sud.

+2

J'ai décroché cette réponse parce que j'ai utilisé cette solution en production, et cela a causé un bug de production. Le problème est que, puisque ce champ ne s'étend pas à AutoField, Django ne récupèrera pas l'ID de la base de données après avoir écrit un nouveau modèle. Il s'agit d'une différence de comportement par rapport aux champs d'incrémentation automatique de l'ID typique. Je vais proposer une solution différente ci-dessous. J'emprunte 99,9% de cette solution, mais je ne veux pas que les autres fassent la même erreur. – Larry

+0

Tks! J'aimerais pouvoir me rappeler où j'en ai besoin avant :-). – lfagundes

+2

Et si vous utilisiez PostgreSQL? Peut-être que nous pourrions ajouter une autre condition dans cette réponse: 'elif 'postgres' dans la connexion .__ classe __.__ module__: return 'bigserial'' – Pawamoy

3

Comme indiqué précédemment, vous pouvez modifier le tableau par la suite. C'est une bonne solution.

Pour ce faire, sans oublier, vous pouvez créer un module de gestion sous votre package d'application et utiliser le signal post_syncdb.

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

Cela peut causer flush django-admin.py à l'échec. Mais c'est toujours la meilleure alternative que je connaisse.

16

Inspiré par lfagundes mais avec une correction petite, mais importante:

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

avis au lieu d'étendre BigIntegerField, je tends AutoField. Cette distinction est importante. Avec AutoField, Django récupèrera l'ID AUTO INCREMENTed de la base de données, contrairement à BigInteger.Une préoccupation lors du passage de BigIntegerField à AutoField a été la conversion des données en int dans AutoField.

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

et

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

Il se trouve que c'est OK, comme l'a vérifié dans une coquille de python:

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

En d'autres termes, la coulée à un int ne tronquera pas le nombre et ne changera pas le type sous-jacent.

+0

J'ai trouvé que j'avais aussi besoin d'un BigForeignKey pour faire Assurez-vous que les types fk sont également mis à bigint – shangxiao

+0

La question de "OK" concernant les appels à int() dans la déclaration de la classe AutoField dépend du système .Si vous êtes sur un système 64 bits, alors sys.maxint retournera La bonne valeur et tout va bien Si pour une raison quelconque en 2015 vous êtes sur un système 32 bits, eh bien, alors Bigint ne fonctionnerait pas de toute façon. –

Questions connexes