Вызовите ошибку проверки в методе сохранения модели в Django - PullRequest
54 голосов
/ 07 января 2012

Я не уверен, как правильно вызвать ошибку проверки в методе сохранения модели и отправить обратно ясное сообщение пользователю.

В основном я хочу знать, как каждая часть "если" должнаконец, тот, где я хочу вызвать ошибку, и тот, где она на самом деле сохраняет:

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

Тогда я хочу знать, что нужно сделать, чтобы отправить ошибку проверки, которая точно говорит пользователю, что простокак тот, который Django автоматически возвращает, если, например, значение не уникально.Я использую (ModelForm) и настраиваю все из модели.

Ответы [ 5 ]

49 голосов
/ 07 января 2012

Большинство просмотров Джанго, например. администратор Django не сможет обработать ошибку проверки в методе сохранения, поэтому ваши пользователи получат 500 ошибок.

Вы должны выполнить проверку в форме модели или на модели и поднять ValidationError там. Затем вызывайте save() только в том случае, если данные формы модели «достаточно хороши для сохранения».

25 голосов
/ 07 января 2012

Бастиан, я объясняю тебе мой шаблонный код, надеюсь, это поможет тебе:

Начиная с 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 Import Issue

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 (): обратите внимание, что full_clean () не будет вызываться автоматически при вызове метода save () вашей модели или в результате проверки ModelForm. Затем вы можете добавить ошибки в словарь форм на без моделей :

    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  )
0 голосов
/ 07 ноября 2018

Редактировать: в этом ответе предполагается, что у вас есть сценарий, который не позволяет редактировать реализуемый в настоящее время класс User, поскольку вы не запускаете проект с нуля, в текущей реализации уже не используется пользовательскийПользовательский класс, и вы вместо этого должны выяснить, как выполнить эту задачу, изменив встроенную в Django модель пользовательской модели.

Вы можете просто прикрепить метод clean к своей модели большую часть времени,но у вас нет такой опции обязательно со встроенной auth.User моделью.Это решение позволит вам создать метод clean для модели auth.User таким образом, чтобы ValidationError s распространялся на формы, где вызывается чистый метод (включая формы администратора).

В приведенном ниже примере возникает ошибка, если кто-то пытается создать или изменить экземпляр auth.User, чтобы он имел тот же адрес электронной почты, что и существующий экземпляр auth.User. Отказ от ответственности, если вы открываете регистрационную форму для новых пользователей, вы не хотите, чтобы ваша ошибка проверки вызвала имена пользователей, как мои ниже.

from django.contrib.auth.models import User
from django.forms import ValidationError as FormValidationError

def clean_user_email(self):
    instance = self
    super(User, self).clean()
    if instance.email:
        if User.objects.filter(id=instance.id, email=instance.email).exists():
            pass  # email was not modified
        elif User.objects.filter(email=instance.email).exists():
            other_users = [*User.objects.filter(email=instance.email).values_list('username', flat=True)]
            raise FormValidationError(f'At least one other user already has this email address: '
                                      f'{", ".join(other_users)}'
                                      , code='invalid')

# assign the above function to the User.clean method
User.add_to_class("clean", clean_user_email)

У меня это внизуиз my_app.models, но я уверен, что это сработает, если вы вставите его в то место, которое загружено перед рассматриваемой формой.

0 голосов
/ 01 декабря 2017
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 голосов
/ 28 сентября 2017

обязательно импортируйте также ошибку ValidationError

from django.core.exceptions import ValidationError
...