2017-05-26 7 views
0

私がしたいことは、モデルの各オブジェクトに対して、固有のラベルがあることです。このラベルは、文字と数字で構成される5文字のランダムな文字列になります。ユニークなものを常に生成することは難しいことです。今、私はそれを次のようやっている:Djangoモデルの場合、5桁のユニークなフィールドを持つ正しい方法は何ですか?

class Order(models.Model): 
    label = models.CharField(max_length=5, unique=True, blank=True) 

    def save(self, *args, **kwargs): 
     if not self.label or self.label == '' or self.label == None: 
      label = '' 
      for i in range(5): 
       label += random.choice(string.lowercase + string.uppercase + string.digits) 
      if Order.objects.filter(label=label).exists(): 
       self.save() # Try again 
      else: 
       self.label = label 
     super(Order, self).save(*args, **kwargs) 

を基本的には、保存する方法は、ラベルを生成し、ラベルは既存のオブジェクトのいずれかと一致した場合、メソッドが再起動されます。しかし、ランダム性の性質上、これをテストすることはほとんど不可能です。この方法でも使えますか?あるいは私は後で問題に遭遇するでしょうか?

また、ラベルが短く読みやすい必要があるため、UUIDなどを提案しないでください。ありがとう。

+0

これらの規格に準拠していない「Order」オブジェクトを追加して何が起こるのを見てみませんか? –

+1

なぜ、数字のIDから順番に生成するのではなく、ラベルを基数62の「数字」とみなしてみませんか?また、テーブルに916,132,832個の要素がある場合は、間違いなく問題にぶつかります。それ以来、一意のラベルがなくなります。 – BrenBarn

+0

私は、落とし穴が最下位の 'super.save'コールだと思います。もし衝突があれば、これは興味深い副作用を持つ可能性がある複数の(おそらく異なるargsで)呼び出されます。 – whp

答えて

1

ShortLinkモデルでshort_idの8つの長さの一意の値を生成するために同様のことを行います。

def save(self, *args, **kwargs): 
    if self.short_id is None: 
     self.short_id = self._generate_random_shortid() 

@classmethod 
def _generate_random_shortid(cls): 
    length = 8 
    char = string.ascii_uppercase + string.digits + string.ascii_lowercase 

    # short_id must be unique 
    while True: 
     short_id = ''.join(random.choice(char) for x in range(length)) 
     try: 
      ShortLink.objects.get(short_id=short_id) 
     except ShortLink.DoesNotExist: 
      return short_id 
関連する問題