2010-04-20 4 views
21

В настоящее время я строил проект, который включает в себя много коллективного интеллекта. Каждый пользователь, посещающий веб-сайт, получает уникальный профиль, и их данные позже используются для расчета наилучших совпадений для самих себя и других пользователей.Поле автоинкремента Django BigInteger в качестве первичного ключа?

По умолчанию Django создает поле INT (11) id для обработки первичных ключей моделей. Я обеспокоен тем, что это очень быстро переполнено (то есть ~ 2.4b устройств, посещающих страницу без предварительной настройки cookie). Как я могу изменить его, чтобы быть представленным как BIGINT в MySQL и long() внутри самого Django?

Я нашел, что я мог бы сделать следующее (http://docs.djangoproject.com/en/dev/ref/models/fields/#bigintegerfield):

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

Но есть способ сделать это Autoincrement, как обычные id полей? Кроме того, могу ли я сделать это без знака, чтобы получить больше места для заполнения?

Спасибо!

ответ

6

После этого вы можете изменить таблицу. Это может быть лучшим решением.

1

У меня также была та же проблема. Похоже, что нет поддержки для автоматических полей BigInteger в django.

Я попытался создать собственное поле BigIntegerAutoField, но у меня возникла проблема с системой южной миграции (юг не смог создать последовательность для моего поля).

Дав попробовать несколько различных подходов, я решил последовать совету Мэтью и делать изменить таблицу (например, ALTER TABLE table_name ALTER COLUMN id TYPE bigint; в Postgre)

Было бы здорово иметь решение при поддержке Джанго (например, встроенный в BigIntegerAutoField) и на юг.

+0

Я думаю, что это не помогло бы, Django будет по-прежнему ставить идентификаторы в нормальный междунар, который еще слишком мал. – letoosh

+0

Совсем нет смысла здесь в том, как идентификатор хранится в базе данных. (Long) целочисленный тип в python имеет «неограниченную» точность. Вы также можете проверить, как BigIntegerField внедряется в Django 1.2 - он наследует непосредственно IntegreField, не меняя внутренний тип, чтобы сохранить значение (которое в этом случае является int) – dzida

+0

Вы правы, мой плохой ... – letoosh

13

ПРИМЕЧАНИЕ: Этот ответ изменен, согласно коду Ларри. Предыдущее решение расширить fields.BigIntegerField, но лучше, чтобы расширить fields.AutoField

У меня была такая же проблема и решена с помощью следующего кода:

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

Видимо, это работает отлично с южными миграций.

+2

У меня есть проголосовавшие этот ответ, потому что я использовал это решение в производстве, и это вызвало ошибку производства. Проблема в том, что, поскольку это поле не расширяет AutoField, Django не будет получать идентификатор из БД после написания новой модели. Это разница в поведении от типичных полей auto auto increment. Ниже я предлагаю другое решение. Я занимаю 99,9% этого решения, но я не хочу, чтобы другие делали ту же ошибку. – Larry

+0

Tks! Хотел бы я вспомнить, где мне это нужно раньше :-). – lfagundes

+2

Что делать, если использовать PostgreSQL? Возможно, мы могли бы добавить еще одно условие в этом ответе: 'elif 'postgres' в связи .__ class __.__ module__: return 'bigserial'' – Pawamoy

3

Как указано выше, вы можете изменить таблицу после этого. Это хорошее решение.

Для этого вы можете создать модуль управления под своим пакетом приложений и использовать сигнал post_syncdb.

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

Это может привести к django-admin.py вровень потерпеть неудачу. Но это все-таки лучшая альтернатива, которую я знаю.

16

Вдохновленный lfagundes, но с небольшой, но важной коррекцией:

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

Уведомление вместо расширения BigIntegerField, я простирающийся AutoField. Это важное различие. С помощью AutoField Django будет извлекать AUTO INCREMENTed id из базы данных, тогда как BigInteger не будет.

Одна из проблем при переходе с BigIntegerField на AutoField заключалась в литье данных в int в AutoField.

Уведомление от 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) 

и

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

Оказывается, это нормально, так как проверяется в оболочке Python:

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

Другими словами, литье к int не будет усекать число, и он не изменит базовый тип.

+0

Я нашел, что мне также потребовался BigForeignKey, чтобы сделать Убедитесь, что типы fk также установлены в bigint. – shangxiao

+0

Вопрос о «ОК» относительно вызовов int() в объявлении класса AutoField зависит от системы. Если вы находитесь в 64-битной системе, тогда sys.maxint вернется правильное значение, и вы в порядке. Если по какой-либо причине в 2015 году вы находитесь на 32-битной системе, ну, тогда Bigint не будет работать в postgres. :-) –