From 4169b1aa3bb90ea5d55ec18d9a2676c35a91f720 Mon Sep 17 00:00:00 2001 From: Ole Magnus Fon Johnsen Date: Thu, 24 Jul 2025 16:44:12 +0200 Subject: [PATCH] Safely cast name as numeric --- src/genlab_bestilling/managers.py | 20 ++++++++++++++++++++ src/staff/views.py | 18 +++--------------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/genlab_bestilling/managers.py b/src/genlab_bestilling/managers.py index 5d019278..18bbd5e0 100644 --- a/src/genlab_bestilling/managers.py +++ b/src/genlab_bestilling/managers.py @@ -3,6 +3,8 @@ from typing import TYPE_CHECKING from django.db import models, transaction +from django.db.models import BigIntegerField, Case, QuerySet, Value, When +from django.db.models.functions import Cast from polymorphic.managers import PolymorphicManager, PolymorphicQuerySet from shared.db import assert_is_in_atomic_block @@ -73,6 +75,24 @@ def filter_in_draft(self) -> QuerySet: order__status=self.model.OrderStatus.DRAFT ) + def annotate_numeric_name(self) -> QuerySet: + """ + Create a new column with the numeric version of the name. + Only if the name is a valid integer, and up to 18 digits, so it fit in a + BigIntegerField. + """ + + return self.annotate( + name_as_int=Case( + When( + name__regex=r"^\d{,18}$", + then=Cast("name", BigIntegerField()), + ), + default=Value(None), + output_field=BigIntegerField(), + ) + ) + @transaction.atomic def generate_genlab_ids( self, diff --git a/src/staff/views.py b/src/staff/views.py index 7c7b8e57..982a10d7 100644 --- a/src/staff/views.py +++ b/src/staff/views.py @@ -3,8 +3,7 @@ from django.contrib import messages from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.db import models -from django.db.models import Case, Count, IntegerField, QuerySet, Value, When -from django.db.models.functions import Cast +from django.db.models import Count, QuerySet from django.forms import Form from django.http import HttpRequest, HttpResponse, HttpResponseRedirect, JsonResponse from django.shortcuts import get_object_or_404, redirect @@ -322,24 +321,13 @@ class Params: sample_id = "sample_id" def get_queryset(self) -> QuerySet[Sample]: - queryset = ( + return ( super() .get_queryset() .select_related("type", "location", "species") .prefetch_related("plate_positions") .filter(order=self.kwargs["pk"]) - ) - - # added to sort based on type (int/str) - return queryset.annotate( - name_as_int=Case( - When( - name__regex=r"^\d+$", - then=Cast("name", IntegerField()), - ), - default=Value(None), - output_field=IntegerField(), - ) + .annotate_numeric_name() ) def get_context_data(self, **kwargs) -> dict[str, Any]: