2010-04-20 8 views
21

Ich baue gerade ein Projekt, das viel kollektive Intelligenz beinhaltet. Jeder Benutzer, der die Website besucht, erstellt ein eindeutiges Profil und seine Daten werden später verwendet, um die besten Übereinstimmungen für sich selbst und andere Benutzer zu berechnen.Django BigInteger Auto-Inkrement-Feld als Primärschlüssel?

Standardmäßig erstellt Django ein Feld INT (11) id, um die Primärschlüssel von Modellen zu verarbeiten. Ich bin besorgt, dass dies sehr schnell überflogen wird (d. H. ~ 2,4b-Geräte, die die Seite ohne vorherige Cookie-Einrichtung besuchen). Wie kann ich es ändern, um als BIGINT in MySQL und Long() in Django selbst dargestellt werden?

ich, ich könnte die folgende (http://docs.djangoproject.com/en/dev/ref/models/fields/#bigintegerfield) tun gefunden habe:

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

Aber gibt es eine Möglichkeit, es autoincrement zu machen, wie üblich id Felder? Kann ich es auch ohne Vorzeichen machen, damit ich mehr Platz zum Ausfüllen habe?

Danke!

Antwort

6

Sie können die Tabelle anschließend ändern. Das könnte eine bessere Lösung sein.

1

Ich hatte auch das gleiche Problem. Sieht so aus, als ob BigInteger-Auto-Felder in Django nicht unterstützt werden.

Ich habe versucht, einige benutzerdefinierte Feld BigIntegerAutoField zu erstellen, aber ich sah ein Problem mit South-Migration-System (South konnte Sequenz für mein Feld nicht erstellen).

Nach versuchen paar verschiedene Ansätze geben habe ich beschlossen, Matthew Rat und ändern Tabelle (z ALTER TABLE table_name ALTER COLUMN id TYPE bigint; in postgre)

Wäre toll zu haben Lösung von django unterstützt zu folgen (wie in BigIntegerAutoField gebaut) und Süden.

+0

ich denke, das würde nicht helfen, da Django noch ids in normalen int setzen würde, die noch zu klein ist. – letoosh

+0

Überhaupt nicht der Punkt hier ist, wie ID in der Datenbank gespeichert ist. (Long) Integer-Typ in Python hat 'unbegrenzte' Genauigkeit. Sie können auch überprüfen, wie BigIntegerField in Django 1.2 implemented ist - es erbt direkt IntegreField, ohne den internen Typ zu ändern, um den Wert zu speichern (was in diesem Fall int ist) – dzida

+0

Sie haben Recht, mein ... – letoosh

13

HINWEIS: Diese Antwort wird gemäß Larrys Code geändert. Bisherige Lösung fields.BigIntegerField verlängert, aber besser zu verlängern fields.AutoField

Ich hatte das gleiche Problem und mit folgendem Code gelöst:

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

Anscheinend arbeitet gut mit Süd-Migrationen.

+2

Ich habe abgelehnt diese Antwort, weil ich diese Lösung in der Produktion verwendet habe und einen Produktionsfehler verursacht hat. Das Problem besteht darin, dass Django die ID nicht aus der Datenbank abruft, nachdem dieses ein neues Modell geschrieben hat, weil dieses Feld AutoField nicht erweitert. Dies ist ein Unterschied im Verhalten von typischen ID-Autoinkrementierungsfeldern. Ich werde unten eine andere Lösung vorschlagen. Ich leihe 99,9% dieser Lösung, aber ich möchte nicht, dass andere den gleichen Fehler machen. – Larry

+0

Tks! Ich wünschte, ich könnte mich erinnern, wo ich das vorher brauche :-). – lfagundes

+2

Was ist, wenn PostgreSQL verwendet wird? Vielleicht könnten wir in dieser Antwort eine weitere Bedingung hinzufügen: 'elif 'postgres' in Verbindung .__ Klasse __.__ module__: return 'bigserial'' – Pawamoy

3

Wie bereits erwähnt, können Sie die Tabelle nachträglich ändern. Das ist eine gute Lösung.

Um das zu tun, ohne zu vergessen, können Sie eine Management-Modul unter dem Anwendungspaket erstellen und das post_syncdb Signal verwenden.

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

Dies kann django-admin.py bündig fehlschlagen verursachen. Aber es ist immer noch die beste Alternative, die ich kenne.

16

von lfagundes inspiriert, aber mit einer kleinen, aber wichtigen Korrektur:

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

Hinweis statt BigIntegerField verlängern, ich bin erstreckt Autofield. Dies ist eine wichtige Unterscheidung. Mit AutoField wird Django die AUTO INCREMENTed ID aus der Datenbank abrufen, BigInteger dagegen nicht.

Ein Problem beim Wechsel von BigIntegerField zu AutoField war das Umwandeln der Daten in ein int in AutoField.

Mitteilung Djangos Autofield:

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) 

und

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

Es stellt sich heraus, das OK ist, wie in einer Python-Shell überprüft:

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

Mit anderen Worten, Gießen zu einem int wird die Zahl nicht abgeschnitten, noch ändert es den zugrunde liegenden Typ.

+0

Ich fand, dass ich auch einen BigForeignKey zu machen brauchte sicher, dass die fk-Typen auch auf bigint gesetzt sind – shangxiao

+0

Die Frage von "OK" bezüglich der Aufrufe von int() in der Deklaration der AutoField-Klasse ist systemabhängig.Wenn Sie auf einem 64-Bit-System sind, wird sys.maxint zurückgeben Der richtige Wert und du bist in Ordnung Wenn du 2015 aus irgendeinem Grund ein 32 Bit System hast, dann würde Bigint sowieso nicht in Postgres funktionieren :-) –

Verwandte Themen