34

モデルレベルでカスタムバリデーターを使用してDjangoモデルオブジェクトを検証する正しい方法を理解しようとしています。検証は通常、フォームまたはモデルフォーム内で行われることを私は知っています。ただし、PythonシェルのORMを介してデータを操作する場合は、モデルレベルでデータの整合性を確保したいと思います。これが私の現在のアプローチです:

from django.db import models
from django.core import validators
from django.core exceptions import ValidationError


def validate_gender(value):
    """ Custom validator """
    if not value in ('m', 'f', 'M', 'F'):
        raise ValidationError(u'%s is not a valid value for gender.' % value)


class Person(models.Model):
    name = models.CharField(max_length=128)
    age = models.IntegerField()
    gender = models.CharField(maxlength=1, validators=[validate_gender])

    def save(self, *args, **kwargs):
        """ Override Person's save """
        self.full_clean(exclude=None)
        super(Person, self).save(*args, **kwargs)

これが私の質問です:

  1. カスタム検証関数を作成し、それをバリデーターとして指定してから、上記のようにPersonのsave()関数をオーバーライドする必要がありますか?(ちなみに、「choices」フィールドオプションを使用して性別の選択を検証できることはわかっていますが、説明のために「validate_gender」を作成しました)。

  2. データの整合性を本当に確保したい場合は、モデルレイヤーでテストするためのDjango単体テストだけでなく、Python / Psycopgを使用した同等のデータベースレベルの単体テストも作成する必要がありますか?ValidationErrorsを発生させるDjangoユニットテストは、データベースのコピーを使用してデータベーススキーマのモデルの理解をテストするだけであることに気づきました。移行にSouthを使用したとしても、データベースレベルの制約は、Djangoが理解してPostgres制約に変換できるものに制限されます。Djangoが複製できないカスタム制約が必要な場合、psqlターミナルを介してデータベースと直接対話していると、その制約に違反するデータをデータベースに入力する可能性があります。

ありがとう!

4

1 に答える 1

23

私が最初に Django を使い始めたとき、ORM について同様の誤解がありました。

  1. self.full_clean()いいえ、中には入れないでくださいsave。また

A) a を使用しますModelForm(これにより、すべて同じ検証が行われます - 注:明示的にModelForm.is_valid()は呼び出されませんModel.full_cleanが、 とまったく同じチェックが実行されますModel.full_clean)。例:

class PersonForm(forms.ModelForm):
    class Meta:
        model = Person

def add_person(request):
    if request.method == 'POST':
        form = PersonForm(request.POST, request.FILES)
        if form.is_valid():  # Performs your validation, including ``validate_gender``
            person = form.save()
            return redirect('some-other-view')
    else:
        form = PersonForm()
        # ... return response with ``form`` in the context for rendering in a template

また、フォームは、テンプレートでレンダリングするビューでのみ使用するためのものではありません。API などを含む、あらゆる種類の使用に最適です。実行form.is_valid()してエラーを取得した後、form.errorsすべてを含む辞書が表示されます。'__all__'フィールド以外のエラーを含む、呼び出されたキーを含む、フォーム内のエラー。

B)model_instance.full_clean()フォームを使用する代わりに、ビュー (または他の論理アプリケーション レイヤー) で使用するだけですが、フォームはこのための優れた抽象化です。

  1. 私は実際に解決策を持っていませんが、大規模なプロジェクト(会社で現在取り組んでいる現在のプロジェクトには146のテーブルがあります)であっても、そのような問題に遭遇したことはありません.あなたの場合の懸念。
于 2012-10-23T20:52:53.720 に答える