Add a 'reference_int' field to the models, to be used as a secondary index

This commit is contained in:
Oliver 2021-10-14 17:45:43 +11:00
parent e46875b0a3
commit 7ce0f817aa
9 changed files with 97 additions and 26 deletions

View File

@ -4,6 +4,7 @@ Generic models which provide extra functionality over base Django model types.
from __future__ import unicode_literals
import re
import os
import logging
@ -43,6 +44,48 @@ def rename_attachment(instance, filename):
return os.path.join(instance.getSubdir(), filename)
class ReferenceIndexingMixin(models.Model):
"""
A mixin for keeping track of numerical copies of the "reference" field.
Here, we attempt to convert a "reference" field value (char) to an integer,
for performing fast natural sorting.
This requires extra database space (due to the extra table column),
but is required as not all supported database backends provide equivalent casting.
This mixin adds a field named 'reference_int'.
- If the 'reference' field can be cast to an integer, it is stored here
- If the 'reference' field *starts* with an integer, it is stored here
- Otherwise, we store zero
"""
class Meta:
abstract = True
def rebuild_reference_field(self):
reference = getattr(self, 'reference', '')
# Default value if we cannot convert to an integer
ref_int = 0
# Look at the start of the string - can it be "integerized"?
result = re.match(r"^(\d+)", reference)
if result and len(result.groups()) == 1:
ref = result.groups()[0]
try:
ref_int = int(ref)
except:
ref_int = 0
self.reference_int = ref_int
reference_int = models.IntegerField(default=0)
class InvenTreeAttachment(models.Model):
""" Provides an abstracted class for managing file attachments.

View File

@ -85,7 +85,7 @@ class BuildList(generics.ListCreateAPIView):
]
ordering_field_aliases = {
'reference': ['integer_ref', 'reference'],
'reference': ['reference_int', 'reference'],
}
search_fields = [

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.5 on 2021-10-14 06:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('build', '0030_alter_build_reference'),
]
operations = [
migrations.AddField(
model_name='build',
name='reference_int',
field=models.IntegerField(default=0),
),
]

View File

@ -28,7 +28,7 @@ from mptt.exceptions import InvalidMove
from InvenTree.status_codes import BuildStatus, StockStatus, StockHistoryCode
from InvenTree.helpers import increment, getSetting, normalize, MakeBarcode
from InvenTree.validators import validate_build_order_reference
from InvenTree.models import InvenTreeAttachment
from InvenTree.models import InvenTreeAttachment, ReferenceIndexingMixin
import common.models
@ -69,7 +69,7 @@ def get_next_build_number():
return reference
class Build(MPTTModel):
class Build(MPTTModel, ReferenceIndexingMixin):
""" A Build object organises the creation of new StockItem objects from other existing StockItem objects.
Attributes:
@ -108,6 +108,8 @@ class Build(MPTTModel):
def save(self, *args, **kwargs):
self.rebuild_reference_field()
try:
super().save(*args, **kwargs)
except InvalidMove:

View File

@ -10,8 +10,7 @@ from django.core.exceptions import ValidationError as DjangoValidationError
from django.utils.translation import ugettext_lazy as _
from django.db.models import Case, When, Value
from django.db.models import BooleanField, IntegerField
from django.db.models.functions import Cast
from django.db.models import BooleanField
from rest_framework import serializers
from rest_framework.serializers import ValidationError
@ -72,11 +71,6 @@ class BuildSerializer(InvenTreeModelSerializer):
)
)
# Annotate with an "integer" version of the reference field, to be used for natural sorting
queryset = queryset.annotate(
integer_ref=Cast('reference', output_field=IntegerField())
)
return queryset
def __init__(self, *args, **kwargs):

View File

@ -156,7 +156,7 @@ class POList(generics.ListCreateAPIView):
]
ordering_field_aliases = {
'reference': ['integer_ref', 'reference'],
'reference': ['reference_int', 'reference'],
}
filter_fields = [
@ -512,7 +512,7 @@ class SOList(generics.ListCreateAPIView):
]
ordering_field_aliases = {
'reference': ['integer_ref', 'reference'],
'reference': ['reference_int', 'reference'],
}
filter_fields = [

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.5 on 2021-10-14 06:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('order', '0050_alter_purchaseorderlineitem_destination'),
]
operations = [
migrations.AddField(
model_name='purchaseorder',
name='reference_int',
field=models.IntegerField(default=0),
),
migrations.AddField(
model_name='salesorder',
name='reference_int',
field=models.IntegerField(default=0),
),
]

View File

@ -28,7 +28,7 @@ from company.models import Company, SupplierPart
from InvenTree.fields import InvenTreeModelMoneyField, RoundingDecimalField
from InvenTree.helpers import decimal2string, increment, getSetting
from InvenTree.status_codes import PurchaseOrderStatus, SalesOrderStatus, StockStatus, StockHistoryCode
from InvenTree.models import InvenTreeAttachment
from InvenTree.models import InvenTreeAttachment, ReferenceIndexingMixin
def get_next_po_number():
@ -89,7 +89,7 @@ def get_next_so_number():
return reference
class Order(models.Model):
class Order(ReferenceIndexingMixin):
""" Abstract model for an order.
Instances of this class:
@ -147,6 +147,9 @@ class Order(models.Model):
return new_ref
def save(self, *args, **kwargs):
self.rebuild_reference_field()
if not self.creation_date:
self.creation_date = datetime.now().date()

View File

@ -4,7 +4,6 @@ JSON serializers for the Order API
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db.models.fields import IntegerField
from django.utils.translation import ugettext_lazy as _
@ -12,7 +11,6 @@ from django.core.exceptions import ValidationError as DjangoValidationError
from django.db import models, transaction
from django.db.models import Case, When, Value
from django.db.models import BooleanField, ExpressionWrapper, F
from django.db.models.functions import Cast
from rest_framework import serializers
from rest_framework.serializers import ValidationError
@ -75,11 +73,6 @@ class POSerializer(InvenTreeModelSerializer):
)
)
# Annotate with an "integer" version of the reference field, to be used for natural sorting
queryset = queryset.annotate(
integer_ref=Cast('reference', output_field=IntegerField())
)
return queryset
supplier_detail = CompanyBriefSerializer(source='supplier', many=False, read_only=True)
@ -435,11 +428,6 @@ class SalesOrderSerializer(InvenTreeModelSerializer):
)
)
# Annotate with an "integer" version of the reference field, to be used for natural sorting
queryset = queryset.annotate(
integer_ref=Cast('reference', output_field=IntegerField())
)
return queryset
customer_detail = CompanyBriefSerializer(source='customer', many=False, read_only=True)