Collection: further improve stoken performance.

We merged the two queries into one and we made it like in the view, so we
can now merge the two instead of having two implementations.
This commit is contained in:
Tom Hacohen 2020-12-04 18:55:22 +02:00
parent bb070639a3
commit 4ce96e043e

View File

@ -17,7 +17,8 @@ from pathlib import Path
from django.db import models, transaction from django.db import models, transaction
from django.conf import settings from django.conf import settings
from django.core.validators import RegexValidator from django.core.validators import RegexValidator
from django.db.models import Max from django.db.models import Max, Value as V
from django.db.models.functions import Coalesce, Greatest
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.crypto import get_random_string from django.utils.crypto import get_random_string
@ -39,6 +40,8 @@ class Collection(models.Model):
main_item = models.OneToOneField("CollectionItem", related_name="parent", null=True, on_delete=models.SET_NULL) main_item = models.OneToOneField("CollectionItem", related_name="parent", null=True, on_delete=models.SET_NULL)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
stoken_id_fields = ["items__revisions__stoken", "members__stoken"]
def __str__(self): def __str__(self):
return self.uid return self.uid
@ -56,9 +59,15 @@ class Collection(models.Model):
@cached_property @cached_property
def stoken(self): def stoken(self):
stoken1 = self.items.aggregate(stoken=Max("revisions__stoken"))["stoken"] or 0 aggr_fields = [Coalesce(Max(field), V(0)) for field in self.stoken_id_fields]
stoken2 = self.members.aggregate(stoken=Max("stoken"))["stoken"] or 0 max_stoken = Greatest(*aggr_fields) if len(aggr_fields) > 1 else aggr_fields[0]
stoken_id = max(stoken1, stoken2) stoken_id = (
self.__class__.objects.filter(main_item=self.main_item)
.annotate(max_stoken=max_stoken)
.values("max_stoken")
.first()["max_stoken"]
)
if stoken_id == 0: if stoken_id == 0:
raise Exception("stoken is None. Should never happen") raise Exception("stoken is None. Should never happen")