Добавление дополнительных ограничений в поля в Django
При подклассовке db.models.Model
иногда необходимо добавить дополнительные проверки/ограничения.
например. У меня есть модель Event
с start_date
и end_date
.
Я хочу добавить проверку в поля или модель, чтобы end_date > start_date
.
Сколько возможных способов сделать это?
По крайней мере, я знаю, что это можно сделать вне models.Model
внутри проверки ModelForm
.
Но как присоединить к полям и models.Model
?
Ответы
Ответ 1
Сделайте это внутри своего метода сохранения вашей модели:
def save(self, *args, **kwargs):
if(self.end_date > self.start_date):
super(Foo, self).save(*args, **kwargs)
else:
raise Exception, "end_date should be greater than start_date"
Ответ 2
Я бы не поставил такие ограничения в методе сохранения, это слишком поздно. Создание исключения там не помогает пользователю, который ввел данные не так, потому что он закончится как 500, и пользователь не получит форму с ошибками и т.д.
Вы действительно должны проверить это в методе очистки Forms/ModelForms и поднять ValidationError, поэтому form.is_valid()
возвращает false, и вы можете отправить ошибки в форме обратно пользователю для исправления.
Также обратите внимание, что с версии 1.2 Django имеет Проверка модели.
Он будет выглядеть примерно так:
class Foo(models.Model):
# ... model stuff...
def clean(self):
if self.start_date > self.end_date:
raise ValidationError('Start date is after end date')
Ответ 3
Как говорит @stefanw, лучше проверить пользовательский способ очистки формы.
Этого достаточно, если вы уверены, что нет и никогда не будет другого способа изменить значение. Но поскольку вы редко можете быть в этом уверены, если важна согласованность базы данных, вы можете добавить еще одну проверку (в дополнение к форме), одну из следующих:
- Более простой и независимый от базы данных способ находится в методе сохранения модели, как сказал @umnik700. Обратите внимание, что это все еще не мешает другим пользователям базы данных (другому приложению или интерфейсу администратора) создавать несогласованное состояние.
-
Чтобы быть полностью "уверенным, что база данных согласована, вы можете добавить ограничение уровня базы данных. Например. вы можете создать миграцию с помощью RunSQL и SQL, что-то вроде (не протестировано):
migrations.RunSQL('ALTER TABLE app_event ADD CONSTRAINT chronology CHECK (start_date > end_date);')
(не проверено). Это может быть зависимым от базы данных, что, конечно, является недостатком.
В вашем примере это, вероятно, не стоит (неправильные времена начала и окончания просто выглядят немного странно, но влияют только на одно несогласованное событие), и вы не хотите изменения ручной схемы. Но это полезно в тех случаях, когда согласованность имеет решающее значение.
EDIT. Вы также можете просто сохранить время начала и продолжительность, а не время начала и окончания.