Повысить погрешность проверки в методе сохранения модели в Django

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

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

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

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

Ответ 1

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

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

Ответ 2

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

Так как django 1.2, он может написать код проверки на модели. Когда мы работаем с modelforms, 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() к моей пользовательской функции, чтобы предотвратить сохранение модели с неправильным состоянием:

from 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 вызывает метод очистки модели, а функция custon проверяет правильное состояние или вызывает ошибку, обрабатываемую формой модели.

Чтобы показать ошибки в форме, вы должны включить это в шаблон формы:

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

Причина в том, что проверка подлинности модели erra ara привязана к записи словаря ошибок 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. Затем вы можете добавить ошибки в словарь формы на 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  )

Ответ 3

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

from django.core.exceptions import ValidationError

Ответ 4

Я думаю, что это более понятный способ сделать это для 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)

Ответ 5

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)

Ответ 6

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

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

В приведенном ниже примере возникает ошибка, если кто-то пытается создать или изменить экземпляр 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 но я уверен, что это будет работать до тех пор, пока вы вставляете его в то место, которое загружено до рассматриваемой формы.