2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-05-01 04:56:45 +00:00

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 from __future__ import unicode_literals
import re
import os import os
import logging import logging
@ -43,6 +44,48 @@ def rename_attachment(instance, filename):
return os.path.join(instance.getSubdir(), 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): class InvenTreeAttachment(models.Model):
""" Provides an abstracted class for managing file attachments. """ Provides an abstracted class for managing file attachments.

View File

@ -85,7 +85,7 @@ class BuildList(generics.ListCreateAPIView):
] ]
ordering_field_aliases = { ordering_field_aliases = {
'reference': ['integer_ref', 'reference'], 'reference': ['reference_int', 'reference'],
} }
search_fields = [ 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.status_codes import BuildStatus, StockStatus, StockHistoryCode
from InvenTree.helpers import increment, getSetting, normalize, MakeBarcode from InvenTree.helpers import increment, getSetting, normalize, MakeBarcode
from InvenTree.validators import validate_build_order_reference from InvenTree.validators import validate_build_order_reference
from InvenTree.models import InvenTreeAttachment from InvenTree.models import InvenTreeAttachment, ReferenceIndexingMixin
import common.models import common.models
@ -69,7 +69,7 @@ def get_next_build_number():
return reference return reference
class Build(MPTTModel): class Build(MPTTModel, ReferenceIndexingMixin):
""" A Build object organises the creation of new StockItem objects from other existing StockItem objects. """ A Build object organises the creation of new StockItem objects from other existing StockItem objects.
Attributes: Attributes:
@ -108,6 +108,8 @@ class Build(MPTTModel):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
self.rebuild_reference_field()
try: try:
super().save(*args, **kwargs) super().save(*args, **kwargs)
except InvalidMove: 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.utils.translation import ugettext_lazy as _
from django.db.models import Case, When, Value from django.db.models import Case, When, Value
from django.db.models import BooleanField, IntegerField from django.db.models import BooleanField
from django.db.models.functions import Cast
from rest_framework import serializers from rest_framework import serializers
from rest_framework.serializers import ValidationError 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 return queryset
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):

View File

@ -156,7 +156,7 @@ class POList(generics.ListCreateAPIView):
] ]
ordering_field_aliases = { ordering_field_aliases = {
'reference': ['integer_ref', 'reference'], 'reference': ['reference_int', 'reference'],
} }
filter_fields = [ filter_fields = [
@ -512,7 +512,7 @@ class SOList(generics.ListCreateAPIView):
] ]
ordering_field_aliases = { ordering_field_aliases = {
'reference': ['integer_ref', 'reference'], 'reference': ['reference_int', 'reference'],
} }
filter_fields = [ 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.fields import InvenTreeModelMoneyField, RoundingDecimalField
from InvenTree.helpers import decimal2string, increment, getSetting from InvenTree.helpers import decimal2string, increment, getSetting
from InvenTree.status_codes import PurchaseOrderStatus, SalesOrderStatus, StockStatus, StockHistoryCode 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(): def get_next_po_number():
@ -89,7 +89,7 @@ def get_next_so_number():
return reference return reference
class Order(models.Model): class Order(ReferenceIndexingMixin):
""" Abstract model for an order. """ Abstract model for an order.
Instances of this class: Instances of this class:
@ -147,6 +147,9 @@ class Order(models.Model):
return new_ref return new_ref
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
self.rebuild_reference_field()
if not self.creation_date: if not self.creation_date:
self.creation_date = datetime.now().date() self.creation_date = datetime.now().date()

View File

@ -4,7 +4,6 @@ JSON serializers for the Order API
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db.models.fields import IntegerField
from django.utils.translation import ugettext_lazy as _ 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 import models, transaction
from django.db.models import Case, When, Value from django.db.models import Case, When, Value
from django.db.models import BooleanField, ExpressionWrapper, F from django.db.models import BooleanField, ExpressionWrapper, F
from django.db.models.functions import Cast
from rest_framework import serializers from rest_framework import serializers
from rest_framework.serializers import ValidationError 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 return queryset
supplier_detail = CompanyBriefSerializer(source='supplier', many=False, read_only=True) 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 return queryset
customer_detail = CompanyBriefSerializer(source='customer', many=False, read_only=True) customer_detail = CompanyBriefSerializer(source='customer', many=False, read_only=True)