35

我目前正在构建一个涉及大量集体智慧的项目。每个访问该网站的用户都会创建一个独特的个人资料,然后他们的数据将用于计算他们自己和其他用户的最佳匹配。

默认情况下,Django 创建一个 INT(11)id字段来处理模型主键。我担心这会很快溢出(即~2.4b 设备在没有事先设置cookie 的情况下访问该页面)。如何将其更改为在 MySQL 中表示为 BIGINT 并在 Django 本身中表示为 long()?

我发现我可以执行以下操作(http://docs.djangoproject.com/en/dev/ref/models/fields/#bigintegerfield):

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

但是有没有办法让它像通常的id字段一样自动递增?另外,我可以把它设为无符号以便我有更多的空间来填写吗?

谢谢!

4

7 回答 7

20

如果您使用的是 Django 1.10,Django 现在有一个内置的 BigAutoField:

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

于 2016-07-27T21:54:48.953 回答
19

受 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 时的一个问题是将数据转换为 AutoField 中的 int。

来自 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)

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

事实证明这没问题,正如在 python shell 中验证的那样:

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

换句话说,转换为 int 不会截断数字,也不会更改基础类型。

于 2013-06-11T02:51:53.317 回答
15

注意:根据拉里的代码,此答案已修改。以前的解决方案扩展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"])

显然,这对南迁来说效果很好。

于 2011-09-16T17:32:27.303 回答
7

之后您可以更改表格。这可能是一个更好的解决方案。

于 2010-04-20T10:17:53.833 回答
3

如前所述,您可以在之后更改表格。这是一个很好的解决方案。

为此,您可以在应用程序包下创建一个管理模块并使用 post_syncdb 信号。

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

这可能会导致 django-admin.py 刷新失败。但它仍然是我所知道的最好的选择。

于 2011-11-22T03:29:19.743 回答
2

我也有同样的问题。看起来 django 中不支持 BigInteger 自动字段。

我试图创建一些自定义字段 BigIntegerAutoField 但我遇到了南迁移系统的问题(南无法为我的字段创建序列)。

在尝试了几种不同的方法后,我决定听从 Matthew 的建议并更改表(例如ALTER TABLE table_name ALTER COLUMN id TYPE bigint;在 postgre 中)

有 django 支持的解决方案(比如内置 BigIntegerAutoField)和南方的解决方案会很棒。

于 2010-06-06T12:33:16.413 回答
2

从 Django 3.2 开始,隐式主键的类型可以通过DEFAULT_AUTO_FIELD设置(文档)来控制。因此,不再需要覆盖所有模型中的主键。

#This setting will change all implicitly added primary keys to BigAutoField
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

请注意,从 Django 3.2 开始,新项目的生成DEFAULT_AUTO_FIELD设置为BigAutoField发行说明)。

于 2021-11-25T14:19:00.947 回答