У меня есть модель Django с датой начала и окончания. Конечная дата может быть нулевой, и если модель активна, она обрабатывается как o .пользовательская проверка в django admin breaks datetime widget
Каждый экземпляр модели имеет поле foo, которое генерируется динамическим списком. Foo не уникален для всех экземпляров, однако два экземпляра с одинаковыми полями foo не могут быть активны одновременно.
База данных, которую я использую, является PostgreSQL, и afaik это не может быть применено на уровне базы данных. Тогда мой выбор заключался в обеспечении этого на уровне администратора. Когда добавляется новый экземпляр моей модели, я хотел бы подтвердить, что в этот момент не было конфликтующих экземпляров, и вызывают ошибку проверки. Когда я собирался протестировать это локально, виджет datetime не отображается вообще, а только текстовое поле.
Мои вопросы - это лучший способ добиться того, чего я хочу, и если да, то почему отсутствует виджет datetime и как его вернуть?
фрагмент кода:
class MyModelAdmin(admin.ModelAdmin):
list_display = ['name',
'foo',
'active',
'created',
'started',
'ended']
list_editable = ['name',
'active',
'ended']
def formfield_for_dbfield(self, db_field, *args, **kwargs):
if db_field.name.lower() == 'foo':
choices = sorted(some_dynamic_list)
db_field.choices = choices
return super().formfield_for_dbfield(db_field, *args, **kwargs)
def get_changelist_form(self, request, *args, **kwargs):
parent_form = super().get_changelist_form(request, *args, **kwargs)
return self.get_childform(parent_form)
def get_form(self, request, obj=None, *args, **kwargs):
parent_form = super().get_form(request, obj, *args, **kwargs)
return self.get_childform(parent_form, obj)
def get_childform(self, parent_form, obj=None):
class ChildForm(parent_form):
def clean(self, *args, **kwargs):
instance_dict = {}
for instance in MyModel.objects.filter(active=True):
foo = instance.config_type.lower()
if foo in instance_dict:
instance_dict[foo].append(instance)
else:
instance_dict[foo] = [instance, ]
if not obj:
for foo, instances in instance_dict.items():
for list_index, instance in enumerate(instances):
for other_instance in instances[list_index + 1:]:
if self.instances_conflict(instance, other_instance):
raise forms.ValidationError("Instances of the same type must not overlap!")
else:
for instance in instance_dict[obj.foo]:
if instance is not obj:
if self.instances_conflict(obj, instance):
raise forms.ValidationError("Instances of the same type must not overlap!")
return super().clean(*args, **kwargs)
def instances_conflict(self, instance_1, instance_2):
if instance_1.ended is None and instance_2.started > instance_1.started:
return True
if instance_2.ended is None and instance_1.started > instance_2.started:
return True
if instance_1.started > instance_2.started and instance_1.started < instance_2.ended:
return True
if instance_2.started > instance_1.started and instance_2.started < instance_1.ended:
return True
return False
return ChildForm
Вы попробовали мой ответ? – e4c5
В конце я использовал для этого специальную форму и поймал эту ситуацию во время проверки. Сдерживания - это то, чего я еще не пробовал. Однако я сделал предваряющий крюк, чтобы вызвать исключение, если это каким-то образом пропустило его мимо модели. Теоретически это означает, что кто-то может сломать это из консоли psql. Я буду уточнять, если я реализую ограничения. – xgadam
он также сломается, если на запрос вызывается функция .update(), потому что для этого не срабатывает сигнал pre_save. – e4c5