web-dev-qa-db-ja.com

Django BigInteger自動インクリメントフィールドを主キーとして?

私は現在、多くの集団的知性を含むプロジェクトを構築しています。 Webサイトにアクセスするすべてのユーザーは一意のプロファイルを作成され、それらのデータは後で自分自身と他のユーザーの最適な一致を計算するために使用されます。

デフォルトでは、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フィールドのように、自動インクリメントする方法はありますか?さらに、それを署名なしにして、記入するスペースを増やすことはできますか?

ありがとう!

25
letoosh

Django 1.10:を使用している場合、DjangoにはBigAutoFieldが組み込まれています。

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

10
Garry Polley

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はデータベースからAUTOINCREMENTed IDを取得しますが、BigIntegerは取得しません。

BigIntegerFieldからAutoFieldに変更する際の1つの懸念は、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にキャストしても、数値が切り捨てられたり、基になる型が変更されたりすることはありません。

19
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"])

どうやらこれは南の移行でうまく機能しています。

14
lfagundes

後でテーブルを変更できます。それはより良い解決策かもしれません。

7

前に述べたように、後でテーブルを変更できます。それは良い解決策です。

これを忘れずに行うには、アプリケーションパッケージの下に管理モジュールを作成し、post_syncdbシグナルを使用します。

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

これにより、Django-admin.pyフラッシュが失敗する可能性があります。しかし、それでも私が知っている最良の選択肢です。

3
rogeliorv

私も同じ問題を抱えていました。 DjangoではBigInteger自動フィールドがサポートされていないようです。

カスタムフィールドBigIntegerAutoFieldを作成しようとしましたが、南の移行システムで問題が発生しました(南はフィールドのシーケンスを作成できませんでした)。

いくつかの異なるアプローチを試した後、私はマシューのアドバイスに従い、テーブルを変更することにしました(例:ALTER TABLE table_name ALTER COLUMN id TYPE bigint; postgre)

Django(BigIntegerAutoFieldに組み込まれているような)とsouthでソリューションがサポートされていると便利です。

2
dzida