TabularInline и ограничение перекрытия диапазона дат

Я использую следующий набор форм, чтобы избежать перекрытия диапазонов дат:

class OccupancyInlineFormset(BaseInlineFormSet):
    def clean(self):
        super().clean()
        for form in self.forms:
            conflicts = Occupancy.objects.filter(unit=form.cleaned_data['unit'], begin__lte=form.cleaned_data['end'], end__gte=form.cleaned_data['begin'])
        if any(conflicts):
            raise ValidationError(_('Overlapping occupancies!'), code='overlap')

В принципе, это работает хорошо, но мой текущий экземпляр Occupancy всегда должен иметь дату окончания 9999-12-31. Когда я изменяю эту дату в форме администратора для текущего экземпляра (и добавляю новый экземпляр с датой окончания 9999-12-31), функция clean() всегда будет вызывать исключение на основе значений, хранящихся в базе данных. Я не очень понимаю, как я мог бы избежать этого, не изменяя нарушающую дату окончания (9999-12-31 → 2023-01-31) сначала в другой (неограниченной) форме, что уничтожает цель формы TabularInline. Спасибо за любую помощь!

После обдумывания проблемы я пришел к следующему (неуклюжему, но работающему) решению:

def clean(self):
    super().clean()
    infinity = datetime.date(9999,12,31)
    for form in self.forms:
        try:
            current_id = form.cleaned_data['id'].pk
        except AttributeError:
            current_id = None
        unit = form.cleaned_data['unit']
        begin = form.cleaned_data['begin']
        end = form.cleaned_data['end']
        # Exclude the instance corresponding to the form and the current occupancy (infinity end date) from the set of conflicting instances
        conflicts = Occupancy.objects.filter(unit=unit, begin__lte=end, end__gte=begin).exclude(pk=current_id).exclude(end=infinity)
    if any(conflicts):
        raise forms.ValidationError(_('Overlapping occupancies!'), code='overlap')
    # if the new occupancy has an infinity end date ...
    elif end == infinity:
        try:
            current_occupancy = Occupancy.objects.get(unit=unit, end=datetime.date(9999,12,31))
            # ... and is not identical with the current occupancy ...
            if current_occupancy.pk != current_id:
                # ... update the current occupancy to end just before the new (infinite) occupancy
                current_occupancy.end = begin - datetime.timedelta(days=1)
                current_occupancy.save()
        except ObjectDoesNotExist:
            pass

При этом учитывается, что экземпляр может перекрывать (по крайней мере, во время очистки входа) сам себя, и что новое занятие с бесконечной датой окончания должно заменить прежнее "текущее" занятие

Вернуться на верх