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

View File

@ -2,6 +2,7 @@ import re
from semver import VersionInfo from semver import VersionInfo
from django.db import models from django.db import models
from django.db.models import ExpressionWrapper, OuterRef, Q, Subquery
from django.core.validators import RegexValidator from django.core.validators import RegexValidator
from membershipworks.models import Member, Flag as MembershipWorksFlag from membershipworks.models import Member, Flag as MembershipWorksFlag
@ -91,12 +92,29 @@ class CertificationDefinition(models.Model):
ordering = ("certification_name", "department") ordering = ("certification_name", "department")
def latest_version(self) -> "CertificationVersion": 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): class CertificationVersion(models.Model):
objects = CertificationVersionManager()
definition = models.ForeignKey( definition = models.ForeignKey(
CertificationDefinition, on_delete=models.PROTECT, db_column="Certification" CertificationDefinition, on_delete=models.PROTECT, db_column="Certification"
) )
@ -117,6 +135,8 @@ class CertificationVersion(models.Model):
) )
] ]
ordering = ("major", "minor", "patch", "prerelease", "approval_date") 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: def semantic_version(self) -> VersionInfo:
return VersionInfo( return VersionInfo(
@ -127,18 +147,6 @@ class CertificationVersion(models.Model):
self.approval_date.isoformat() if self.approval_date is not None else None, 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): class Certification(models.Model):
number = models.AutoField(db_column="Number", primary_key=True) number = models.AutoField(db_column="Number", primary_key=True)