2016-06-21 15 views
0

ランダムな文字列を生成する(unique_id)というモデルフィールドがあります。それはモデル呼出しで定義されています。モデルフィールド一意性検証のエラー処理

unique_id = models.CharField(db_index=True, default=generate_id()) 

generate_id機能は、それが一意ではありませんでした場合

import random 
a = 'ABCDEFJHIJKLMNOPQRSTUVWXYZabcdefjhijklmnopqrstuvwxyz_-123456789'  

def generate_id(length=6): 
     return ''.join(random.choice(a) for i in range(length)) 

DjangoはIntegrityError: UNIQUE constraint failedが発生しますです。

データベースレベルで一意のIDSが重複しないようにするにはどうすればよいでしょうか?

+3

デフォルトの属性で関数を呼び出すべきではないことに注意してください。呼び出し可能なもの自体を渡すだけです。 –

+0

ヘッドアップありがとうございます。 – static

答えて

2

defaultの値をcallableに設定することができます。これはオブジェクトが作成されるたびに関数を呼び出すためですが、フィールドdefinitそれは

unique_id = models.CharField(db_index=True, default=generate_id) 

intepret時間に一度呼び出されます上の第二に、私はあなたのためにランダムな文字列の生成を行いである、UUIDFieldを使用することをお勧めします。

問題を解決するには2つの方法があります。 unique_idかなり長い12文字以上の長さを生成します。これにより、衝突が発生しないことがほとんど保証されます。それとも、この方法では、あなたのgenerate_id機能

def generate_id(length=6): 
    unique_id = ''.join(random.choice(a) for i in range(length)) 
    while Mymodel.objects.filter(unique_id=unique_id).exists(): 
     unique_id = ''.join(random.choice(a) for i in range(length)) 
    return unique_id 

答えるコメント モデルが

class Post(models.Model): 
    def _generate_id(self, length=6): 
     unique_id = ''.join(random.choice(a) for i in range(length)) 
     while self.__class__.objects.filter(unique_id=unique_id).exists(): 
      unique_id = ''.join(random.choice(a) for i in range(length)) 
     return unique_id 

以下の例のようにself.__class__を介してアクセスすることができる。しかし、それはあなたがしません方法になる場合には、DBのチェックを追加することができますselfインスタンスが存在しないため、デフォルト値としてフィールドに追加できます。しかし、@classmethodデコレータを試してみることもできます。これは、オブジェクトをインスタンス化する前に_generate_idを定義し、@classmethodsとしか動作しない場合にのみ可能です。これは、Pythonクラスが独自の小さな名前空間であるためです。

class Post(models.Model): 
    @classmethod 
    def _generate_id(cls, length=6): 
     unique_id = ''.join(random.choice(a) for i in range(length)) 
     while cls.objects.filter(unique_id=unique_id).exists(): 
      unique_id = ''.join(random.choice(a) for i in range(length)) 
     return unique_id 

    unique_id = models.CharField(db_index=True, default=_generate_id, max_length=12) 

しかし、私は実生活でこれを試したことはありません。

+0

明確化のためにありがとう、モデル自体を参照する方法(ポスト)はありますか? 'Post._generate_id'メソッドを定義しようとしていますので、モデルの中でデフォルトとして使うことができます。 – static

+0

@staticクラス内にgenerate_idを持つことはできません。 –

+1

更新された回答を読む。通常は、メソッドのようなgenerate_idを使う必要はありませんが、 '@ classmethod'デコレータの2番目の例がまだ必要な場合は –

0

したがって、モデル宣言の問題は、デフォルトでgenerate_id()を使用しているため、その呼び出しの出力がデフォルトとして使用されています。

IDにオブジェクトが作成されるたびに発生する、これは

unique_id = models.CharField(db_index=True, default=generate_id)

この呼んで使用してみてください

参考:@DanielRosemanはdefaultで関数を呼び出すことはありません言ったようにまずhttps://docs.djangoproject.com/en/1.9/ref/models/fields/#default

+0

これは、ランダムなIDの作成をどのようにして停止させるのですか? – Sayse

+0

、そうでないと、generate_id関数のロジックが正しいはずです。上記の質問のために、まったく同じ値が繰り返し与えられます。 generate_idが10を返した場合にpythonファイルを実行しているときのように、保存されたオブジェクトごとに同じ特定のプロセスに対して値10が返されます。だから、呼び出し可能にすることで、オブジェクトが作成されるたびに関数が呼び出されることが保証されます。 –

関連する問題