简体   繁体   中英

Django QuerySet filter by Range with DateTimeField

I tried to fix my queryset method, checked some answers on Stackoverflow, but still couldn't do it.

Basically i want to validate my form, so when there is an lesson within ceratin range, a Student cannot propose this specific timerange to it's lesson.

The problem is that when i try to find a queryset withing DateTimeField that exists, i still got an empty queryset:

My model:

class Lesson(models.Model):
    student = models.ForeignKey(User, on_delete=models.CASCADE)
    subject = models.ForeignKey(Classroom, on_delete=models.CASCADE)
    description = models.CharField(max_length = 200)
    start_time = models.DateTimeField()
    end_time = models.DateTimeField()
    accepted = models.BooleanField(default=False)

Method in form:

def clean(self):
    cleaned_data = super().clean()
    lesson_start_time = cleaned_data.get('start_time')
    lesson_end_time = cleaned_data.get('end_time')
    
    queryset = Lesson.objects.filter(start_time__range=(lesson_start_time,lesson_end_time))
    print(lesson_start_time) #2022-08-23 15:44:00+00:00
    print(lesson_end_time) #2022-08-23 15:36:00+00:00
    print(queryset) # <QuerySet []>
    
    if lesson_end_time < lesson_start_time:
        raise ValidationError("End time cannot be lower than start time!")

And there is for sure a Lesson Object within this range.

What i know for now is that it requeries something else to filter DateTimeField by range, but everything that i tried didn't work (for example: Django - Filter objects by DateTimeField with a date range ).

Could you please help me?

That is possible: two ranges can overlap, without that the start time or end time is within the "range" of the other object. For example if the second object is fully contained by the first object.

You can fix this by first determining when two ranges do not overlap. Two ranges [s 1 , e 1 ] and [s 2 , e 2 ] do not overlap if s 1 <e 2 , or e 1 <s 2 . We can negate this expression to know when two intervals overlap: s 1 ≤e 2 , and e 1 ≥s 2 .

This thus means that we can check this with:

def clean(self):
    cleaned_data = super().clean()
    start = cleaned_data['start_time']
    end = cleaned_data['end_time']

    queryset = Lesson.objects.exclude(pk=self.instance.pk).filter(
        
    )
    if end <= start:
        raise ValidationError('End time cannot be lower than start time!')
    if queryset.exists():
        raise ValidationError('There is an item with overlap!')
    return cleaned_data

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM