21

次の(簡略化された)データ構造があります。

Site
-> Zone
   -> Room
      -> name

各ルームの名前をサイトごとに一意にしたい。

各ゾーンの一意性だけが必要な場合は、次のようにすることができます。

class Room(models.Model):
    zone = models.ForeignKey(Zone)
    name = models.CharField(max_length=255) 

    class Meta:
        unique_together = ('name', 'zone')

しかし、私は本当にやりたいことができません。

class Room(models.Model):
    zone = models.ForeignKey(Zone)
    name = models.CharField(max_length=255) 

    class Meta:
        unique_together = ('name', 'zone__site')

この質問で示唆されているように、validate_unique メソッドを追加してみました:

class Room(models.Model):
    zone = models.ForeignKey(Zone)
    name = models.CharField(max_length=255) 

    def validate_unique(self, exclude=None):
        qs = Room.objects.filter(name=self.name)
        if qs.filter(zone__site=self.zone__site).exists():
            raise ValidationError('Name must be unique per site')

        models.Model.validate_unique(self, exclude=exclude)

しかし、Room オブジェクトを保存するときに呼び出されないため、validate_unique のポイント/実装を誤解しているに違いありません。

このチェックを実装する正しい方法は何でしょうか?

4

3 に答える 3

20

モデルを保存するとき、メソッドは単独では呼び出されません。これを行う 1 つの方法は、モデルの保存時に validate_unique メソッドを呼び出すカスタムの save メソッドを用意することです。

class Room(models.Model):
    zone = models.ForeignKey(Zone)
    name = models.CharField(max_length=255) 

    def validate_unique(self, exclude=None):
        qs = Room.objects.filter(name=self.name)
        if qs.filter(zone__site=self.zone__site).exists():
            raise ValidationError('Name must be unique per site')


    def save(self, *args, **kwargs):

        self.validate_unique()

        super(Room, self).save(*args, **kwargs)
于 2013-01-23T01:25:24.427 に答える
8
class Room(models.Model):
    zone = models.ForeignKey(Zone)
    name = models.CharField(max_length=255)

    def validate_unique(self, *args, **kwargs):
        super(Room, self).validate_unique(*args, **kwargs)
        qs = Room.objects.filter(name=self.name)
        if qs.filter(zone__site=self.zone__site).exists():
            raise ValidationError({'name':['Name must be unique per site',]})

同様のプログラムを作成する必要がありました。出来た。

于 2015-02-27T11:33:22.977 に答える
6

Django Validation objects documentation は、このスニペットを含む検証に関連する手順を説明しています

モデルの save() メソッドを呼び出しても、 full_clean() は自動的に呼び出されないことに注意してください

を使用した結果としてモデル インスタンスが作成されているModelForm場合、フォームの検証時に検証が行われます。

検証の処理方法にはいくつかのオプションがあります。

  1. full_clean()保存する前にモデル インスタンスを手動で呼び出します。
  2. モデルのメソッドをオーバーライドして、save()保存のたびに検証を実行します。ここで、完全な検証を行うか、一意性チェックのみを行うか、どの程度の検証を行うかを選択できます。

    class Room(models.Model):
        def save(self, *args, **kwargs):
            self.full_clean()
            super(Room, self).save(*args, **kwargs)
    
  3. 保存前に自動的に検証を実行するDjango pre_saveシグナル ハンドラーを使用します。これにより、モデル コードを追加することなく、既存のモデルに検証を追加するための非常に簡単な方法が提供されます。

    # In your models.py
    from django.db.models.signals import pre_save
    
    def validate_model_signal_handler(sender, **kwargs):
        """
        Signal handler to validate a model before it is saved to database.
        """
        # Ignore raw saves.
        if not kwargs.get('raw', False):
            kwargs['instance'].full_clean()
    
    
    pre_save.connect(validate_model_signal_handler,
      sender=Room,
      dispatch_uid='validate_model_room')
    
于 2013-01-23T04:11:26.483 に答える