7

モデルの主キーを無署名にしたい。したがって、私はこのようなことをします:

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

これUNSIGNEDにより、結果の MySQL テーブルに必要な列が取得されます。idただし、新しいオブジェクトを作成するたびに自動的に割り当てられるとは思えませんね。AutoFieldこれには、代わりに を使用する必要があるようです。問題は、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

編集:明確にするために、私自身またはシマナスが作成したソリューションは、実際のプロジェクトでは使用しないでください。これは、DBMS 組み込みの方法を避けることにした場合にどの方向に進むべきかの例として書いたものであり、すぐに使用できる完成したモデルとしてではありません。

シマナスの投稿にコメントの代わりに回答を書いて申し訳ありませんが、投稿する評判は高くありません。この質問は「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の回答と比較して、クロスデータベースで機能します。

この方法のもう 1 つの注意点は、別のアプリケーションが同じデータベースにフックしている場合、自動インクリメンタルはデータベース レベルで行われないため、INSERT で ID を提供する必要があることです。

ほとんどの場合、このようにしたくありません。

于 2014-07-27T09:36:44.337 に答える