Django BigInteger自增字段作为主键?
我现在正在做一个项目,这个项目涉及到很多用户的共同智慧。每个访问网站的用户都会被创建一个独特的个人资料,他们的数据会被用来计算他们和其他用户之间的最佳匹配。
默认情况下,Django会创建一个INT(11)的id
字段来处理模型的主键。我担心这个字段会很快溢出(也就是说,大约有24亿个设备访问这个页面而没有设置之前的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
字段那样自动递增呢?另外,我能不能把它设置为无符号,这样我就能有更多的空间来填充数据?
谢谢!
7 个回答
受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会从数据库中获取自动递增的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命令行中验证过:
>>> l2 = 99999999999999999999999999999
>>> type(l2)
<type 'long'>
>>> int(l2)
99999999999999999999999999999L
>>> type(l2)
<type 'long'>
>>> type(int(l2))
<type 'long'>
换句话说,转换成int类型不会截断数字,也不会改变底层的数据类型。
如果你使用的是Django 1.10,现在它内置了一个叫做BigAutoField的功能:
https://docs.djangoproject.com/en/1.10/ref/models/fields/#bigautofield
从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
。