2010-04-20 12 views
21

Obecnie tworzę projekt, który wymaga dużej zbiorowej inteligencji. Każdy użytkownik odwiedzający witrynę otrzymuje unikalny profil, a dane są później wykorzystywane do obliczania najlepszych dopasowań dla siebie i innych użytkowników.Automatyczne pole przyrostowe Django BigIntegera jako klucz podstawowy?

Domyślnie Django tworzy pole INT (11) id do obsługi kluczy podstawowych modeli. Obawiam się, że jest to bardzo szybko przepełnione (tj. ~ 2,4b urządzenia odwiedzające stronę bez wcześniejszej konfiguracji plików cookie). Jak mogę go zmienić, aby był reprezentowany jako BIGINT w MySQL i long() wewnątrz samego Django?

Znalazłem mogę wykonać następujące czynności (http://docs.djangoproject.com/en/dev/ref/models/fields/#bigintegerfield):

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

Ale czy jest jakiś sposób, aby to autoIncrement, jak zwykle id polach? Dodatkowo, czy mogę uczynić go niepodpisanym, aby uzyskać więcej miejsca do wypełnienia?

Dzięki!

Odpowiedz

6

Możesz później zmienić stół. To może być lepsze rozwiązanie.

1

Też miałem ten sam problem. Wygląda na to, że w django nie ma obsługi pól automatycznych BigInteger.

Próbowałem utworzyć niestandardowe pole BigIntegerAutoField, ale napotkałem problem z południowym systemem migracji (na południu nie można utworzyć sekwencji dla mojego pola).

Po udzieleniu kilku try różnych podejść postanowiłem podążać porady Mateusza i zrobić alter table (np ALTER TABLE table_name ALTER COLUMN id TYPE bigint; w Postgre)

Byłoby wspaniale mieć rozwiązanie obsługiwane przez Django (jak zbudowany w BigIntegerAutoField) i południe.

+0

myślę, że to nie pomoże, jak Django nadal szuka identyfikatora do normalnej int, który jest wciąż zbyt mała. – letoosh

+0

Wcale nie, chodzi o to, jak id jest przechowywany w bazie danych. (Long) typ całkowity w pythonie ma precyzję "nieograniczoną". Możesz także sprawdzić, w jaki sposób BigIntegerField jest wbudowany w Django 1.2 - dziedziczy bezpośrednio IntegreField, bez zmiany wewnętrznego typu, aby zapisać wartość (co w tym przypadku jest int). – dzida

+0

Masz rację, moja zła ... – letoosh

13

UWAGA: Ta odpowiedź została zmodyfikowana zgodnie z kodem Larry'ego. Poprzednie rozwiązanie przedłużony fields.BigIntegerField, ale lepiej rozszerzyć fields.AutoField

miałem ten sam problem i rozwiązać za pomocą następującego kodu:

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

Widocznie ten działa poprawnie z migracji na południe.

+2

Głosowałem w dół ta odpowiedź, ponieważ użyłem tego rozwiązania w produkcji i spowodowało błąd produkcyjny. Problem polega na tym, że ponieważ to pole nie rozszerza AutoField, Django nie pobierze identyfikatora z DB po napisaniu nowego modelu. Jest to różnica w zachowaniu od typowych pól automatycznego przyrostu identyfikatora. Poniżej przedstawię propozycję innego rozwiązania. Pożyczam 99,9% tego rozwiązania, ale nie chcę, aby inni popełnili ten sam błąd. – Larry

+0

Tks! Szkoda, że ​​nie pamiętam, gdzie potrzebuję tego wcześniej :-). – lfagundes

+2

Co zrobić, jeśli korzystasz z PostgreSQL? Może moglibyśmy dodać inny warunek w tej odpowiedzi: 'elif 'postgres' w związku .__ klasa __.__ moduł__: return 'bigserial'' – Pawamoy

3

Jak wcześniej wspomniano, można później zmienić tabelę. To dobre rozwiązanie.

Aby to zrobić, nie zapominając, możesz utworzyć moduł zarządzania w pakiecie aplikacji i użyć sygnału post_syncdb.

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

może to spowodować django-admin.py równo na niepowodzenie. Ale to wciąż najlepsza alternatywa, jaką znam.

16

Zainspirowany lfagundes ale z małym ale ważnej korekty:

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

Wskazówka zamiast przedłużenia BigIntegerField, mam rozszerzenie AutoField. To ważne rozróżnienie. Dzięki AutoField Django pobierze AUTO INCREMENTed id z bazy danych, natomiast BigInteger nie.

Jedną z obaw przy zmianie z BigIntegerField na AutoField było odlewanie danych do int w AutoField.

Zawiadomienie Django 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) 

i

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

Okazuje się, to jest OK, jako zweryfikowane w powłoce Pythona:

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

Innymi słowy, odlew do int nie obciąje liczby, ani nie zmieni typu bazowego.

+0

Znalazłem, że potrzebowałem również klucza BigForeignKey do zrobienia upewnij się, że typy fk również są ustawione na bigint – shangxiao

+0

Pytanie "OK" dotyczące wywołań int() w deklaracji klasy AutoField zależy od systemu.Jeśli jesteś w systemie 64-bitowym, to sys.maxint zwróci odpowiednią wartość i jesteś w porządku. Jeśli z jakiegokolwiek powodu w 2015 roku będziesz w systemie 32-bitowym, cóż, to Bigint i tak nie będzie działał w postgresach :-) –