Отображение исключений проверки пользовательской модели на сайте администратора Django
У меня есть модель бронирования, которая должна проверить, доступен ли доступный предмет. Я бы хотел, чтобы логика выясняла, доступен ли элемент централизованно, так что независимо от того, где я сохраняю экземпляр, этот код подтверждает, что он может быть сохранен.
В настоящий момент у меня есть этот код в пользовательской функции сохранения моего класса модели:
def save(self):
if self.is_available(): # my custom check availability function
super(MyObj, self).save()
else:
# this is the bit I'm stuck with..
raise forms.ValidationError('Item already booked for those dates')
Это отлично работает - ошибка возникает, если элемент недоступен, и мой элемент не сохраняется. Я могу зафиксировать исключение из моего кода формы переднего конца, но как насчет сайта администратора Django? Как я могу заставить свое исключение отображаться как любая другая ошибка проверки на сайте администратора?
Ответы
Ответ 1
В django 1.2 добавлена проверка модели.
Теперь вы можете добавить "чистый" метод к вашим моделям, которые увеличивают исключения ValidationError, и он будет вызываться автоматически при использовании администратора django.
(Не ясно в документации, что метод clean вызывается администратором, но я проверил его здесь)
http://docs.djangoproject.com/en/dev/ref/models/instances/?from=olddocs#validating-objects
Таким образом, ваш чистый метод может быть примерно таким:
from django.core.exceptions import ValidationError
class MyModel(models.Model):
def is_available(self):
#do check here
return result
def clean(self):
if not self.is_available():
raise ValidationError('Item already booked for those dates')
Я не использовал его широко, но, похоже, гораздо меньше кода, чем создание ModelForm, а затем связать эту форму в файле admin.py для использования в django admin.
Ответ 2
Вот вы: http://docs.djangoproject.com/en/dev/ref/contrib/admin/#adding-custom-validation-to-the-admin Это, однако, может быть ортогонально тому, как вы это сделали. Это не должно быть ошибкой проверки, которую вы поднимаете, потому что они выражаются формами. В любом случае, посмотрите и выберите способ, который вам нравится.
Ответ 3
Я также пытался решить эту проблему, и есть мое решение. В моем случае мне нужно было отклонить любые изменения в связанных объектах, если main_object заблокирован для редактирования.
1) пользовательское исключение
class Error(Exception):
"""Base class for errors in this module."""
pass
class EditNotAllowedError(Error):
def __init__(self, msg):
Exception.__init__(self, msg)
2) metaclass с пользовательским методом сохранения - все мои модели related_data будут основаны на этом:
class RelatedModel(models.Model):
main_object = models.ForeignKey("Main")
class Meta:
abstract = True
def save(self, *args, **kwargs):
if self.main_object.is_editable():
super(RelatedModel, self).save(*args, **kwargs)
else:
raise EditNotAllowedError, "Closed for editing"
3) metaform - все мои связанные с этим_файлы админов будут основаны на этом (это гарантирует, что интерфейс администратора будет информировать пользователя без ошибки интерфейса администратора):
from django.forms import ModelForm, ValidationError
...
class RelatedModelForm(ModelForm):
def clean(self):
cleaned_data = self.cleaned_data
if not cleaned_data.get("main_object")
raise ValidationError("Closed for editing")
super(RelatedModelForm, self).clean() # important- let admin do its work on data!
return cleaned_data
На мой взгляд, это не так много накладных расходов и все еще довольно просто и удобно.
Ответ 4
Довольно старый пост, но я думаю, что использование пользовательской очистки - это все же принятый ответ. Но это неудовлетворительно. Вы можете сделать как можно больше предварительной проверки, поскольку вы хотите получить исключение в Model.save()
, и вы можете показать сообщение пользователю в соответствии с ошибкой проверки формы.
Я нашел решение, чтобы переопределить ModelAdmin.changeform_view(). В этом случае я обнаруживаю ошибку целостности, сгенерированную где-то в драйвере SQL:
def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
try:
return super(MyModelAdmin, self).changeform_view(request, object_id, form_url, extra_context)
except IntegrityError as e:
self.message_user(request, e, level=messages.ERROR)
return HttpResponseRedirect(form_url)