web-dev-qa-db-ja.com

Djangoのモデルのsaveメソッドで検証エラーを発生させます

モデルのsaveメソッドで検証エラーを適切に発生させ、ユーザーに明確なメッセージを送り返す方法がわかりません。

基本的に、「if」の各部分、エラーを発生させたい部分と実際に保存する部分を終了する方法を知りたいです。

def save(self, *args, **kwargs):
    if not good_enough_to_be_saved:
        raise ValidationError
    else:
        super(Model, self).save(*args, **kwargs)

次に、たとえば値が一意でない場合にDjangoが自動的に返すように。 (ModelForm)およびモデルのすべてを調整します。

55
Bastian

ほとんどのDjangoビューたとえばDjango adminはsaveメソッドで検証エラーを処理できないため、ユーザーは500エラーを受け取ります。

モデルフォームまたはモデルで検証を行い、そこでValidationErrorを上げる必要があります。次に、モデルフォームデータが「保存するのに十分な」場合にのみ、save()を呼び出します。

51
Alasdair

バスティアン、私はあなたに私のコードテンプレートを説明します、それがあなたに役立つことを願っています:

Django 1.2では、モデルに検証コードを記述できます 。モデルフォームを操作する場合、フォームの検証時にinstance.full_clean()が呼び出されます。

各モデルでclean()メソッドをカスタム関数で上書きします(このメソッドは、モデルフォームの検証時にfull_clean()から自動的に呼び出されます):

_from Django.db import models

class Issue(models.Model):
    ....
    def clean(self): 
        rules.Issue_clean(self)  #<-- custom function invocation

from issues import rules
rules.connect()
_

次に、_rules.py_ファイルにビジネスルールを記述します。また、pre_save()をカスタム関数に接続して、誤った状態でモデルを保存しないようにします。

issues.modelsインポートから

_def connect():    
    from Django.db.models.signals import post_save, pre_save, pre_delete
    #issues 
    pre_save.connect(Issue_pre_save, sender = Incidencia ) 
    post_save.connect(Issue_post_save, sender = Incidencia )
    pre_delete.connect(Issue_pre_delete, sender= Incidencia) 

def Incidencia_clean( instance ):    #<-- custom function 
    import datetime as dt    
    errors = {}

    #dia i hora sempre informats     
    if not instance.dia_incidencia:   #<-- business rules
        errors.setdefault('dia_incidencia',[]).append(u'Data missing: ...')

    #dia i hora sempre informats     
    if not  instance.franja_incidencia: 
        errors.setdefault('franja_incidencia',[]).append(u'Falten Dades: ...')

    #Només es poden posar incidències més ennlà de 7 dies 
    if instance.dia_incidencia < ( dt.date.today() + dt.timedelta( days = -7) ): 
        errors.setdefault('dia_incidencia 1',[]).append(u'''blah blah error desc)''')

    #No incidències al futur. 
    if instance.getDate() > datetime.now(): 
        errors.setdefault('dia_incidencia 2',[]).append(u'''Encara no pots ....''') 
    ... 

    if len( errors ) > 0: 
        raise ValidationError(errors)  #<-- raising errors

def Issue_pre_save(sender, instance, **kwargs): 
    instance.clean()     #<-- custom function invocation
_

次に、modelformはモデルのcleanメソッドを呼び出し、custon関数が正しい状態をチェックするか、モデルフォームによって処理されるエラーを発生させます。

フォームにエラーを表示するには、フォームテンプレートにこれを含める必要があります。

_{% if form.non_field_errors %}
      {% for error in form.non_field_errors %}
        {{error}}
      {% endfor %}
{% endif %}  
_

その理由は、モデル検証エラーがnon_field_errorsエラーディクショナリエントリにバインドされているためです。

フォームからモデルを保存または削除するとき、エラーが発生する可能性があることを覚えておく必要があります。

_try:
    issue.delete()
except ValidationError, e:
    import itertools
    errors = list( itertools.chain( *e.message_dict.values() ) )
_

また、モデルフォームなしでフォーム辞書にエラーを追加できます。

_    try:
        #provoco els errors per mostrar-los igualment al formulari.
        issue.clean()
    except ValidationError, e:
        form._errors = {}
        for _, v in e.message_dict.items():
            form._errors.setdefault(NON_FIELD_ERRORS, []).extend(  v  )
_

このコードはsave()メソッドで実行されないことに注意してください:モデルのsave()メソッドを呼び出したとき、またはModelForm検証の結果として、full_clean()は自動的に呼び出されないことに注意してください。次に、no modelformsのフォームディクショナリにエラーを追加できます。

_    try:
        #provoco els errors per mostrar-los igualment al formulari.
        issue.clean()
    except ValidationError, e:
        form._errors = {}
        for _, v in e.message_dict.items():
            form._errors.setdefault(NON_FIELD_ERRORS, []).extend(  v  )
_
25
dani herrera

validationErrorも必ずインポートしてください

from Django.core.exceptions import ValidationError
1
Brendan
def clean(self):
    raise ValidationError("Validation Error")

def save(self, *args, **kwargs):
    if some condition:
        #do something here
    else:
        self.full_clean()
    super(ClassName, self).save(*args, **kwargs)
0
Asif Akhtar

これは、Django 1.2+

フォームでは、non_field_errorとして発生します。他のケースでは、DRFのように、500エラーになるため、このケースのマニュアルを確認する必要があります。

class BaseModelExt(models.Model):
is_cleaned = False

def clean(self):
    # check validation rules here

    self.is_cleaned = True

def save(self, *args, **kwargs):
    if not self.is_cleaned:
        self.clean()

    super().save(*args, **kwargs)
0
megajoe