Skip to content

Commit caba079

Browse files
committed
Enhance admin queryset performance with select_related and annotations
1 parent cb33cf7 commit caba079

File tree

3 files changed

+69
-11
lines changed

3 files changed

+69
-11
lines changed

invoicing/admin.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ def queryset(self, request, queryset):
4040
class InvoiceAdmin(admin.ModelAdmin):
4141
change_list_template = "admin/invoice_change_list.html"
4242

43+
def get_queryset(self, request):
44+
return super().get_queryset(request).select_related('member')
45+
4346
def invoice_actions(self, obj):
4447
if obj.member is not None:
4548
color = 'orange'
@@ -212,6 +215,9 @@ class ResourceAdmin(admin.ModelAdmin):
212215

213216
ordering = ['category', 'name']
214217

218+
def get_queryset(self, request):
219+
return super().get_queryset(request).select_related('account', 'widget', 'category', 'unit')
220+
215221

216222
admin.site.register(Resource, ResourceAdmin)
217223

@@ -237,6 +243,19 @@ def queryset(self, request, queryset):
237243

238244
class UsageAdmin(admin.ModelAdmin):
239245

246+
def get_queryset(self, request):
247+
queryset = super().get_queryset(request)
248+
queryset = queryset.select_related(
249+
'member',
250+
'project',
251+
'project__member',
252+
'resource',
253+
'resource__unit',
254+
'invoice',
255+
'invoice__member',
256+
)
257+
return queryset
258+
240259
def export_as_csv(self, request, queryset):
241260

242261
response = HttpResponse(content_type='text/csv')
@@ -285,6 +304,9 @@ def has_delete_permission(self, request, obj=None):
285304
class AccountEntryAdmin(admin.ModelAdmin):
286305
list_display = ['date', 'member', 'amount_machine', 'amount_cash', 'comment', 'invoice']
287306

307+
def get_queryset(self, request):
308+
return super().get_queryset(request).select_related('member', 'invoice', 'invoice__member')
309+
288310

289311
class ExpenseAdmin(admin.ModelAdmin):
290312
list_display = ['member', 'date', 'amount', 'topaye', 'processed']

members/admin.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
from django.contrib import admin
2+
from django.db.models import Count, Q
23
from django.urls import reverse
34
from django.utils.html import format_html
45

56
from .models import Member, Project, ProjectCard
6-
from invoicing.models import Invoice
77
from django.http import HttpResponse
88
import csv
99

@@ -12,24 +12,41 @@ class ProjectAdmin(admin.ModelAdmin):
1212
list_display = ['name', 'member']
1313
search_fields = ['name', 'member__name', 'member__surname']
1414

15+
def get_queryset(self, request):
16+
return super().get_queryset(request).select_related('member')
17+
1518

1619
admin.site.register(Project, ProjectAdmin)
1720

1821

1922
class ProjectCardAdmin(admin.ModelAdmin):
2023
list_display = ['project', 'rfid']
2124

25+
def get_queryset(self, request):
26+
return super().get_queryset(request).select_related('project', 'project__member')
27+
2228

2329
admin.site.register(ProjectCard, ProjectCardAdmin)
2430

2531

2632
class MemberAdmin(admin.ModelAdmin):
2733
actions = ['export_as_mail_list', 'export_as_mail_csv']
2834

35+
def get_queryset(self, request):
36+
return super().get_queryset(request).annotate(
37+
open_invoices_count=Count(
38+
'invoice',
39+
filter=~Q(invoice__status__in=('paid', 'cancelled'))
40+
)
41+
)
42+
43+
@staticmethod
44+
def _get_mail_list(queryset):
45+
return queryset.in_mail_list().values_list('mail', flat=True)
46+
2947
def export_as_mail_list(self, request, queryset):
3048
response = HttpResponse()
31-
32-
mails = [member.mail for member in queryset if member.mail and member.is_in_mail_list]
49+
mails = self._get_mail_list(queryset)
3350
response.write(';'.join(mails))
3451
return response
3552

@@ -42,17 +59,15 @@ def export_as_mail_csv(self, request, queryset):
4259
)
4360

4461
writer = csv.writer(response)
45-
46-
mails = [member.mail for member in queryset if member.mail and member.is_in_mail_list]
47-
for mail in mails:
62+
for mail in self._get_mail_list(queryset):
4863
writer.writerow([mail])
4964

5065
return response
5166

5267
export_as_mail_csv.short_description = "Export Email as CSV"
5368

5469
def members_actions(self, obj):
55-
open_invoices = Invoice.objects.filter(member=obj).exclude(status__in=('paid', 'cancelled')).count()
70+
open_invoices = obj.open_invoices_count
5671
color = 'darkgreen'
5772
if open_invoices > 0:
5873
color = 'darkorange'
@@ -69,7 +84,6 @@ def formatted_name(self, member):
6984
return member.name
7085

7186

72-
7387
list_display = ['members_actions', 'formatted_name', 'surname', 'rfid', 'is_staff', 'is_committee']
7488
list_display_links = ['formatted_name', 'surname']
7589
search_fields = ['name', 'surname', 'rfid', 'visa']

members/models.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,25 @@ class ProjectCard(models.Model):
1212
def __str__(self):
1313
return f'{self.project} {self.rfid}'
1414

15+
16+
MAIL_LIST_EXCLUDED_STATUSES = ['resigned']
17+
MAIL_LIST_EXCLUDED_TYPES = ['no_member']
18+
19+
20+
class MemberQuerySet(models.QuerySet):
21+
def in_mail_list(self):
22+
return self.exclude(
23+
subscription_status__in=MAIL_LIST_EXCLUDED_STATUSES,
24+
).exclude(
25+
member_type__in=MAIL_LIST_EXCLUDED_TYPES,
26+
).filter(
27+
date_resigned__isnull=True,
28+
mail__isnull=False,
29+
).exclude(
30+
mail='',
31+
)
32+
33+
1534
class Member(models.Model):
1635
INSCRIPTION_STATE = [
1736
('not member', 'not member'),
@@ -70,6 +89,8 @@ class Member(models.Model):
7089
swiss_engineering_number = models.CharField('Numéro de membre Swiss Engineering', max_length=200, default=None, null=True, blank=True)
7190
comment = models.TextField('Commentaire', max_length=2000, default=None, null=True, blank=True)
7291

92+
objects = MemberQuerySet.as_manager()
93+
7394
@property
7495
def get_tariff(self):
7596
if self.subscription_status not in ['resigned']:
@@ -83,9 +104,10 @@ def get_tariff(self):
83104

84105
@property
85106
def is_in_mail_list(self):
86-
return self.subscription_status not in ['resigned'] \
87-
and self.member_type not in['no_member'] \
88-
and not self.is_resigned
107+
return self.subscription_status not in MAIL_LIST_EXCLUDED_STATUSES \
108+
and self.member_type not in MAIL_LIST_EXCLUDED_TYPES \
109+
and not self.is_resigned \
110+
and bool(self.mail)
89111

90112
@property
91113
def is_resigned(self):

0 commit comments

Comments
 (0)