paperwork: Convert CertificationVersion is_current/latest to annotations

Pretty sigificantly improves performance of views that use it
This commit is contained in:
Adam Goldsmith 2023-02-01 00:11:28 -05:00
parent 1dd4825a99
commit bb0e5abad5
2 changed files with 37 additions and 17 deletions

View File

@ -37,6 +37,14 @@ class CertificationVersionInline(admin.TabularInline):
"is_current",
)
@admin.display(description="Latest", boolean=True)
def is_latest(self, obj):
return obj.is_latest
@admin.display(description="Current", boolean=True)
def is_current(self, obj):
return obj.is_current
@admin.register(CertificationDefinition)
class CertificationDefinitionAdmin(admin.ModelAdmin):
@ -64,6 +72,10 @@ class CertificationAdmin(admin.ModelAdmin):
autocomplete_fields = ["member"]
exclude = ["shop_lead_notified"]
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.prefetch_related("certification_version__definition__department")
@admin.display(
description="Certification Name",
ordering="certification_version__definition__certification_name",
@ -87,8 +99,8 @@ class CertificationAdmin(admin.ModelAdmin):
return obj.certification_version.semantic_version()
@admin.display(description="Current", boolean=True)
def certification_version__is_current(self, obj):
return obj.certification_version.is_current()
def is_current(self, obj):
return obj.certification_version.is_current
@admin.display(
description="Department",
@ -101,7 +113,7 @@ class CertificationAdmin(admin.ModelAdmin):
"certification_name",
"name",
"certification_semantic_version",
"certification_version__is_current",
"is_current",
"certification_department",
"date",
"shop_lead_notified",

View File

@ -2,6 +2,7 @@ import re
from semver import VersionInfo
from django.db import models
from django.db.models import ExpressionWrapper, OuterRef, Q, Subquery
from django.core.validators import RegexValidator
from membershipworks.models import Member, Flag as MembershipWorksFlag
@ -91,12 +92,29 @@ class CertificationDefinition(models.Model):
ordering = ("certification_name", "department")
def latest_version(self) -> "CertificationVersion":
all_versions = CertificationVersion.objects.filter(definition=self)
return self.certificationversion_set.latest()
return max(all_versions, key=lambda version: version.semantic_version())
class CertificationVersionManager(models.Manager):
def get_queryset(self):
qs = super().get_queryset()
latest = qs.filter(definition__pk=OuterRef("definition__pk"))
return qs.annotate(
is_latest=ExpressionWrapper(
Q(pk=Subquery(latest.values("pk")[:1])),
output_field=models.BooleanField(),
),
# TODO: should do a more correct comparison than just major version
is_current=ExpressionWrapper(
Q(major=Subquery(latest.values("major")[:1])),
output_field=models.BooleanField(),
),
)
class CertificationVersion(models.Model):
objects = CertificationVersionManager()
definition = models.ForeignKey(
CertificationDefinition, on_delete=models.PROTECT, db_column="Certification"
)
@ -117,6 +135,8 @@ class CertificationVersion(models.Model):
)
]
ordering = ("major", "minor", "patch", "prerelease", "approval_date")
get_latest_by = ("major", "minor", "patch", "prerelease", "approval_date")
base_manager_name = "objects"
def semantic_version(self) -> VersionInfo:
return VersionInfo(
@ -127,18 +147,6 @@ class CertificationVersion(models.Model):
self.approval_date.isoformat() if self.approval_date is not None else None,
)
def is_latest(self) -> bool:
return self.definition.latest_version() == self
is_latest.boolean = True
def is_current(self) -> bool:
"""Returns true if this version compatible with the latest version"""
# TODO: should do a more correct comparison than just major version
return self.definition.latest_version().major == self.major
is_current.boolean = True
class Certification(models.Model):
number = models.AutoField(db_column="Number", primary_key=True)