0001-manager-slug-generation-optimization-on-event-import.patch
chrono/agendas/models.py | ||
---|---|---|
68 | 68 |
return dtime.hour == 0 and dtime.minute == 0 |
69 | 69 | |
70 | 70 | |
71 |
def generate_slug(instance, **query_filters): |
|
71 |
def generate_slug(instance, seen_slugs=None, **query_filters):
|
|
72 | 72 |
base_slug = instance.base_slug |
73 | 73 |
slug = base_slug |
74 | 74 |
i = 1 |
75 |
while instance._meta.model.objects.filter(slug=slug, **query_filters).exists(): |
|
75 | ||
76 |
if seen_slugs is None: |
|
77 |
# no optimization: check slug in DB each time |
|
78 |
while instance._meta.model.objects.filter(slug=slug, **query_filters).exists(): |
|
79 |
slug = '%s-%s' % (base_slug, i) |
|
80 |
i += 1 |
|
81 |
return slug |
|
82 | ||
83 |
# seen_slugs is filled |
|
84 |
while True: |
|
85 |
if slug not in seen_slugs: |
|
86 |
# check in DB to be sure, but only if not seen |
|
87 |
queryset = instance._meta.model.objects.filter(slug=slug, **query_filters) |
|
88 |
if not queryset.exists(): |
|
89 |
break |
|
76 | 90 |
slug = '%s-%s' % (base_slug, i) |
77 | 91 |
i += 1 |
92 |
seen_slugs.add(slug) |
|
78 | 93 |
return slug |
79 | 94 | |
80 | 95 | |
... | ... | |
810 | 825 |
if self.cancellation_scheduled: |
811 | 826 |
return _('Cancellation in progress') |
812 | 827 | |
813 |
def save(self, *args, **kwargs): |
|
828 |
def save(self, seen_slugs=None, *args, **kwargs):
|
|
814 | 829 |
assert self.agenda.kind != 'virtual', "an event can't reference a virtual agenda" |
815 | 830 |
assert not (self.slug and self.slug.isdigit()), 'slug cannot be a number' |
816 | 831 |
self.check_full() |
817 | 832 |
if not self.slug: |
818 |
self.slug = generate_slug(self, agenda=self.agenda) |
|
833 |
self.slug = generate_slug(self, seen_slugs=seen_slugs, agenda=self.agenda)
|
|
819 | 834 |
return super(Event, self).save(*args, **kwargs) |
820 | 835 | |
821 | 836 |
@property |
chrono/manager/views.py | ||
---|---|---|
1337 | 1337 | |
1338 | 1338 |
def form_valid(self, form): |
1339 | 1339 |
if form.events: |
1340 |
# existing event slugs for this agenda |
|
1341 |
seen_slugs = set(self.agenda.event_set.values_list('slug', flat=True)) |
|
1340 | 1342 |
for event in form.events: |
1341 | 1343 |
event.agenda_id = self.kwargs['pk'] |
1342 |
event.save()
|
|
1344 |
event.save(seen_slugs=seen_slugs) # optimization: seen_slugs
|
|
1343 | 1345 |
messages.info(self.request, _('%d events have been imported.') % len(form.events)) |
1344 | 1346 |
return super(AgendaImportEventsView, self).form_valid(form) |
1345 | 1347 |
tests/test_manager.py | ||
---|---|---|
1581 | 1581 |
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200) |
1582 | 1582 |
resp.form['events_csv_file'] = Upload( |
1583 | 1583 |
't.csv', |
1584 |
b'2016-09-16,18:00,10,5,label,,,pricing,\n' |
|
1585 |
b'2016-09-17,18:00,10,5,label,,,pricing,\n' |
|
1586 |
b'2016-09-18,18:00,10,5,label,,,pricing,\n', |
|
1584 |
b'2016-09-16,18:00,10,5,labela,,,pricing,\n' |
|
1585 |
b'2016-09-17,18:00,10,5,labela,,,pricing,\n' |
|
1586 |
b'2016-09-18,18:00,10,5,labela,,,pricing,\n' |
|
1587 |
b'2016-09-18,18:00,10,5,labelb,,,pricing,\n' |
|
1588 |
b'2016-09-18,18:00,10,5,labelb,,,pricing,\n', |
|
1587 | 1589 |
'text/csv', |
1588 | 1590 |
) |
1589 |
resp = resp.form.submit(status=302) |
|
1590 |
assert Event.objects.count() == 3 |
|
1591 |
with CaptureQueriesContext(connection) as ctx: |
|
1592 |
resp = resp.form.submit(status=302) |
|
1593 |
assert len(ctx.captured_queries) == 24 |
|
1594 |
assert Event.objects.count() == 5 |
|
1591 | 1595 | |
1592 | 1596 |
# forbidden numerical slug |
1593 | 1597 |
Event.objects.all().delete() |
1594 |
- |