Skip to content

Commit

Permalink
Merge branch 'develop' into flexible-end-#541
Browse files Browse the repository at this point in the history
  • Loading branch information
the-moog committed Feb 9, 2023
2 parents 0a17ede + 8aa6f87 commit f795b59
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 23 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG
@@ -1,6 +1,7 @@
0.10.? - 2022-09-10
0.10.1 - 2023-01-29
===================

- Periods performance improvement avoid nplus queries
- Make event.end optional so that it can later be updated with a known value

0.10.0 - 2022-08-21
Expand Down
23 changes: 12 additions & 11 deletions schedule/models/events.py
Expand Up @@ -187,7 +187,7 @@ def get_occurrences(self, start, end, clear_prefetch=True):
# to override this cache clear since it already fetches all
# occurrence_sets via prefetch_related in its get_occurrences.
if clear_prefetch:
self.occurrence_set._remove_prefetched_objects()
self.refresh_from_db()

persisted_occurrences = self.occurrence_set.all()
occ_replacer = OccurrenceReplacer(persisted_occurrences)
Expand Down Expand Up @@ -626,10 +626,11 @@ class Meta:

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if not self.title and self.event_id:
self.title = self.event.title
if not self.description and self.event_id:
self.description = self.event.description
event = kwargs.get("event", None)
if not self.title and event:
self.title = event.title
if not self.description and event:
self.description = event.description

def moved(self):
return self.original_start != self.start or self.original_end != self.end
Expand Down Expand Up @@ -665,12 +666,12 @@ def get_absolute_url(self):
if self.pk is not None:
return reverse(
"occurrence",
kwargs={"occurrence_id": self.pk, "event_id": self.event.id},
kwargs={"occurrence_id": self.pk, "event_id": self.event_id},
)
return reverse(
"occurrence_by_date",
kwargs={
"event_id": self.event.id,
"event_id": self.event_id,
"year": self.start.year,
"month": self.start.month,
"day": self.start.day,
Expand All @@ -684,12 +685,12 @@ def get_cancel_url(self):
if self.pk is not None:
return reverse(
"cancel_occurrence",
kwargs={"occurrence_id": self.pk, "event_id": self.event.id},
kwargs={"occurrence_id": self.pk, "event_id": self.event_id},
)
return reverse(
"cancel_occurrence_by_date",
kwargs={
"event_id": self.event.id,
"event_id": self.event_id,
"year": self.start.year,
"month": self.start.month,
"day": self.start.day,
Expand All @@ -703,12 +704,12 @@ def get_edit_url(self):
if self.pk is not None:
return reverse(
"edit_occurrence",
kwargs={"occurrence_id": self.pk, "event_id": self.event.id},
kwargs={"occurrence_id": self.pk, "event_id": self.event_id},
)
return reverse(
"edit_occurrence_by_date",
kwargs={
"event_id": self.event.id,
"event_id": self.event_id,
"year": self.start.year,
"month": self.start.month,
"day": self.start.day,
Expand Down
15 changes: 7 additions & 8 deletions schedule/periods.py
Expand Up @@ -89,14 +89,13 @@ def _get_sorted_occurrences(self):
and occurrence.end >= self.utc_start
):
occurrences.append(occurrence)
return occurrences

prefetch_related_objects(self.events, "occurrence_set")
for event in self.events:
event_occurrences = event.get_occurrences(
self.start, self.end, clear_prefetch=False
)
occurrences += event_occurrences
else:
prefetch_related_objects(self.events, "occurrence_set")
for event in self.events:
event_occurrences = event.get_occurrences(
self.start, self.end, clear_prefetch=False
)
occurrences += event_occurrences
return sorted(occurrences, **self.sorting_options)

def cached_get_sorted_occurrences(self):
Expand Down
2 changes: 1 addition & 1 deletion schedule/views.py
Expand Up @@ -399,7 +399,7 @@ def convert(ddatetime):
# event, using the "event_id" or the occurrence with the specified "id".
# for more info https://github.com/llazzaro/django-scheduler/pull/169
i = 1
if Occurrence.objects.all().count() > 0:
if Occurrence.objects.all().exists():
i = Occurrence.objects.latest("id").id + 1
event_list = []
for calendar in calendars:
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = django-scheduler
version = 0.10.0
version = 0.10.1
description = A calendaring app for Django.
long_description = file: README.md
long_description_content_type = text/markdown
Expand Down
40 changes: 39 additions & 1 deletion tests/test_periods.py
Expand Up @@ -2,10 +2,12 @@

import pytz
from django.conf import settings
from django.db import connection
from django.test import TestCase
from django.test.utils import override_settings
from django.test.utils import CaptureQueriesContext, override_settings

from schedule.models import Calendar, Event, Rule
from schedule.models.events import Occurrence
from schedule.periods import Day, Month, Period, Week, Year


Expand Down Expand Up @@ -38,6 +40,42 @@ def test_get_occurrences(self):
],
)

def test_nplus_one_queries_event_period(self):
"""Reproduces bug 420 occurences without title or desc will generate additional queries
to retrieve the event model
"""
rule = Rule.objects.create(frequency="WEEKLY")
cal = Calendar.objects.get(name="MyCal")

event = Event.objects.create(
title="TEST",
start=datetime.datetime(2008, 1, 5, 8, 0, tzinfo=pytz.utc),
end=datetime.datetime(2023, 1, 5, 9, 0, tzinfo=pytz.utc),
end_recurring_period=datetime.datetime(2008, 5, 5, 0, 0, tzinfo=pytz.utc),
rule=rule,
calendar=cal,
)
for _ in range(0, 21):
# lets set occ without title and desc to use the event.title or event.desc
Occurrence.objects.create(
event=event,
start=datetime.datetime(2008, 1, 7, 8, 0, tzinfo=pytz.utc),
end=datetime.datetime(2008, 1, 7, 8, 0, tzinfo=pytz.utc),
original_start=datetime.datetime(2008, 1, 7, 8, 0, tzinfo=pytz.utc),
original_end=datetime.datetime(2008, 1, 7, 8, 0, tzinfo=pytz.utc),
)
period = Period(
events=[event],
start=datetime.datetime(2008, 1, 4, 7, 0, tzinfo=pytz.utc),
end=datetime.datetime(2023, 1, 21, 7, 0, tzinfo=pytz.utc),
)
with CaptureQueriesContext(connection) as ctx:
for occurrence in period.get_occurrences():
pass

executed_queries = len(ctx.captured_queries)
assert executed_queries == 1, len(ctx.captured_queries)

def test_get_occurrences_with_sorting_options(self):
period = Period(
events=Event.objects.all(),
Expand Down

0 comments on commit f795b59

Please sign in to comment.