2012-10-23 6 views
23

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

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. は私がバリデータとして指定、カスタム検証関数を作成し、私は「として人のsave()関数をオーバーライドする必要があります上でやった? (ところで、「選択肢」フィールドオプションを使用して性別の選択肢を検証することができますが、説明のために「validate_gender」を作成しました)。私は本当にが私のデータの整合性を確保したい場合

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

ありがとう!

+0

質問1がこのトピックに関する以前の質問とどのように異なるかわかりません。ただし、ORMを使用して無効なデータを挿入することはできません。 'Person.objects.update(gender = 'a')'を考えてみましょう。 – Alasdair

+1

私の前回の質問では、私がここで行ったように私はカスタムバリデータ関数を含んでいなかった点を除いて、あなたは正しいです。 .updateについてのあなたの他の見解については、今や混乱の原因となる追加の問題があると思います。私は本当にこれを行う正しい方法が何であるかを理解することに本当に苦労しています。 Djangoのドキュメントはかなり優れていますが、IMHOは断片的で「手を振って」いるだけですが、この問題を解決する正しい方法を理解するのに役立つ完全な例については不十分です。残念ながら、私は一人で作業し、経験豊富な開発者がこれについて議論する必要はありません。 – William

答えて

16

私はDjangoを使い始めたときにORMの誤解がありました。

1)いいえ、self.full_clean()saveの中に入れないでください。どちらの

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 

はまた、フォームはテンプレートのみでそれらをレンダリングビューで使用するためにはありませんが、注意してください - 彼らはエラーをform.is_valid()を実行して取得した後などのAPIを含め、使用の任意の並べ替えのために素晴らしいです、フィールド内のエラーを含む'__all__'というキーを含むフォーム内のすべてのエラーを含む辞書であるform.errorsがあります。

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

2)私は実際には解決策がありませんが、大規模なプロジェクトでもこのような問題に遭遇したことはありません。(私の会社とは146テーブルあります)あなたのケースでもそれが懸念されると思われます。

+2

実際のテンプレートフォームのモデルオブジェクトをユーザーに実際に提示していない場合でも、データモデルを検証するためにフォームまたはモデルフォームを使用する必要がありますか?ありがとう。 – William

+1

@RobertF。 - そのとおりです。 'ModelForm'クラスは、テンプレートのフォームを表示するつもりがない場合でも、モデルの検証のための適切な抽象化です。 – orokusaki

+1

あなたはA)これを行うか、オプションBはどちらかと言いましたか? – rgenito

関連する問題