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