Django BigInteger自动增量字段作为主键?

let*_*osh 25 python django biginteger primary-key auto-increment

我目前正在建立一个涉及大量集体智慧的项目.访问该网站的每个用户都会创建一个独特的配置文件,他们的数据稍后将用于为自己和其他用户计算最佳匹配.

默认情况下,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)
Run Code Online (Sandbox Code Playgroud)

但有没有办法让它像通常的id田地一样自动增量?另外,我可以将它设为无符号,以便我可以填充更多空间吗?

谢谢!

Lar*_*rry 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"])
Run Code Online (Sandbox Code Playgroud)

请注意,我没有扩展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)
Run Code Online (Sandbox Code Playgroud)

def get_prep_value(self, value):
    if value is None:
        return None
    return int(value)
Run Code Online (Sandbox Code Playgroud)

事实证明这是正常的,如在python shell中验证的那样:

>>> l2 = 99999999999999999999999999999
>>> type(l2)
<type 'long'>
>>> int(l2)
99999999999999999999999999999L
>>> type(l2)
<type 'long'>
>>> type(int(l2))
<type 'long'>
Run Code Online (Sandbox Code Playgroud)

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


lfa*_*des 14

注意:根据Larry的代码,这个答案被修改了.以前的解决方案扩展了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"])
Run Code Online (Sandbox Code Playgroud)

显然,这对南方迁移来说很好.

  • 我已经对这个答案进行了投票,因为我在生产中使用了这个解决方案,并且它导致了生产错误.问题是因为这个字段没有扩展AutoField,所以Django在编写新模型后不会从DB中获取ID.这是典型的id自动增量字段的行为差异.我将在下面提出不同的解决方案.我借了这个解决方案的99.9%,但我不希望别人犯同样的错误. (2认同)
  • 如果使用PostgreSQL会怎么样?也许我们可以在这个答案中添加另一个条件:`elif'postgres'in connection .__ class __.__ module__:return'bigserial'` (2认同)

Gar*_*ley 10

如果您使用Django 1.10,Django现在内置了BigAutoField:

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


Mat*_*kel 7

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


小智 7

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

#This setting will change all implicitly added primary keys to BigAutoField
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
Run Code Online (Sandbox Code Playgroud)

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