7

我希望我的模型的主键未签名。因此我做这样的事情:

class MyModel(models.Model):
    id = models.PositiveIntegerField(primary_key=True)

这让我得到了UNSIGNED我想要的结果 MySQL 表中的一列。但是,我相信id每次创建新对象时都不会自动分配,对吗?这似乎需要使用 ofAutoField来代替。问题是,AutoField签名。有没有办法创建一个 unsigned AutoField

4

2 回答 2

5

字段的实际类型在后端指定。在 MySQL 的情况下,后端是django.db.backends.mysql. 此摘录django/db/backends/mysql/creation.py显示此翻译:

class DatabaseCreation(BaseDatabaseCreation):
    # This dictionary maps Field objects to their associated MySQL column
    # types, as strings. Column-type strings can contain format strings; they'll
    # be interpolated against the values of Field.__dict__ before being output.
    # If a column type is set to None, it won't be included in the output.
    data_types = {
        'AutoField':         'integer AUTO_INCREMENT',
        'BooleanField':      'bool',
        'CharField':         'varchar(%(max_length)s)',
        ...

要改变这一点,您应该对这个 dict 进行猴子修补:

from django.db.backends.mysql.creation import DatabaseCreation
DatabaseCreation.data_types['AutoField'] = 'integer UNSIGNED AUTO_INCREMENT'

或者您创建自己的课程,这样您就不会弄乱其他课程AutoFields

from django.db.models.fields import AutoField
class UnsignedAutoField(AutoField):
    def get_internal_type(self):
        return 'UnsignedAutoField'

from django.db.backends.mysql.creation import DatabaseCreation
DatabaseCreation.data_types['UnsignedAutoField'] = 'integer UNSIGNED AUTO_INCREMENT'

然后创建自己的 PK:

id = UnsignedAutoField()

当它从 下降时AutoField,它将继承其所有行为。

于 2013-08-29T15:24:26.300 回答
0

编辑:为了清楚起见,我自己或 Simanas 编写的解决方案都不应该在现实世界的项目中使用。我写这个是作为一个例子,如果他们决定避免使用 DBMS 内置方式,应该朝哪个方向发展,而不是作为一个完整的模型准备好使用。

我很抱歉写了一个答案而不是评论 Simanas 的帖子,但我没有很高的声誉来发布一个,我觉得这是必要的,因为这个问题在 'django autofield unsigned integer' 关键字中排名很高。

使用他的方法是不可靠的,因为如果先前的对象之一被删除,它将为新行生成一个现有的整数。这是一个修改过的:

from django.db import IntegrityError
import re

class MyModel(models.Model):

    def next_id():
        try:
            # Find the ID of the last object
            last_row = MyModel.objects.order_by('-id')[0]
            return last_row.id + 1
        except IndexError:
            # No objects exist in database so far
            return 1

    id = models.PositiveIntegerField(primary_key=True, default=next_id)

    def save(self, *args, **kwargs):
        while True:
            try:
                super(MyModel, self).save(*args, **kwargs)
                break
            except IntegrityError, e:
                if e.args[0] == 1062:
                    if re.match("^Duplicate entry \'.*\' for key \'%s\'$"
                            % re.escape(self._meta.pk.name), e.args[1]):
                        self.id = next_id()
                    else:
                        raise

虽然这可行,但它不知道新分配的 ID 是否以前用于另一个对象(在删除最新对象的情况下?),并且在这种情况下可能导致冲突;但与 MySQL 特定的 Augusto 的答案相比,它可以跨数据库工作。

此方法的另一个警告是,如果您有另一个应用程序连接到同一个数据库,它必须在 INSERT 上提供 ID,因为自动增量不是在数据库级别完成的。

你几乎肯定不想这样做。

于 2014-07-27T09:36:44.337 回答