Поле автоинкремента Django BigInteger в качестве первичного ключа? - PullRequest
24 голосов
/ 20 апреля 2010

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

По умолчанию 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)

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

Спасибо!

Ответы [ 6 ]

17 голосов
/ 11 июня 2013

Вдохновлен 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 из базы данных, а BigInteger - нет.

Одной из проблем при переходе с BigIntegerField на AutoField было преобразование данных в int в 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 не будет усекать число и не будет изменять базовый тип.

14 голосов
/ 16 сентября 2011

ПРИМЕЧАНИЕ. Этот ответ изменен в соответствии с кодом Ларри. Предыдущее решение расширяло поля. BigIntegerField, но лучше расширять поля. 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"])

Очевидно, это хорошо работает с миграциями на юг.

8 голосов
/ 28 июля 2016

Django теперь имеет встроенное BigAutoField, если вы используете Django 1.10:

https://docs.djangoproject.com/en/1.10/ref/models/fields/#bigautofield

7 голосов
/ 20 апреля 2010

Вы можете изменить таблицу позже. Это может быть лучшим решением.

3 голосов
/ 22 ноября 2011

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

Чтобы сделать это, не забывая, вы можете создать модуль управления в вашем приложении и использовать сигнал post_syncdb.

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

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

2 голосов
/ 06 июня 2010

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

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

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

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

...