perf(wpm): batch load handover inventory validation
This commit is contained in:
parent
d98b7fada2
commit
24ce008d3a
|
|
@ -1265,7 +1265,26 @@ class Handoverbwserializer(CustomModelSerializer):
|
|||
read_only_fields = EXCLUDE_FIELDS_BASE + ["handoverb", "number"]
|
||||
extra_kwargs = {'wpr': {'required': True}}
|
||||
|
||||
|
||||
class CachedWMaterialPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
|
||||
def to_internal_value(self, data):
|
||||
cache = getattr(self.root, "_handover_wmaterial_cache", None)
|
||||
if cache is None:
|
||||
return super().to_internal_value(data)
|
||||
if not isinstance(data, (str, int)):
|
||||
self.fail("incorrect_type", data_type=type(data).__name__)
|
||||
try:
|
||||
return cache[str(data)]
|
||||
except KeyError:
|
||||
self.fail("does_not_exist", pk_value=data)
|
||||
|
||||
|
||||
class HandoverbSerializer(CustomModelSerializer):
|
||||
wm = CachedWMaterialPrimaryKeyRelatedField(
|
||||
queryset=WMaterial.objects.select_related(
|
||||
"material", "defect", "mgroup", "belong_dept"
|
||||
)
|
||||
)
|
||||
notok_sign = serializers.CharField(source='wm.notok_sign', read_only=True)
|
||||
defect_name = serializers.CharField(source="wm.defect.name", read_only=True)
|
||||
handoverbw = Handoverbwserializer(many=True, required=False)
|
||||
|
|
@ -1301,6 +1320,27 @@ class HandoverSerializer(CustomModelSerializer):
|
|||
wm_notok_sign = serializers.CharField(source='wm.notok_sign', read_only=True)
|
||||
handoverb = HandoverbSerializer(many=True, required=False)
|
||||
ticket_ = TicketSimpleSerializer(source='ticket', read_only=True)
|
||||
|
||||
def to_internal_value(self, data):
|
||||
handoverb = data.get("handoverb", []) if hasattr(data, "get") else []
|
||||
wm_ids = {
|
||||
str(item["wm"])
|
||||
for item in handoverb
|
||||
if isinstance(item, dict) and item.get("wm") is not None
|
||||
}
|
||||
if not wm_ids:
|
||||
return super().to_internal_value(data)
|
||||
|
||||
queryset = WMaterial.objects.select_related(
|
||||
"material", "defect", "mgroup", "belong_dept"
|
||||
)
|
||||
self._handover_wmaterial_cache = {
|
||||
str(pk): instance for pk, instance in queryset.in_bulk(wm_ids).items()
|
||||
}
|
||||
try:
|
||||
return super().to_internal_value(data)
|
||||
finally:
|
||||
del self._handover_wmaterial_cache
|
||||
|
||||
def validate(self, attrs):
|
||||
if "mtype" not in attrs:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
from django.db import connection
|
||||
from django.test import TestCase
|
||||
from django.test.utils import CaptureQueriesContext
|
||||
|
||||
from apps.mtm.models import Material
|
||||
from apps.qm.models import Defect
|
||||
from apps.system.models import Dept, User
|
||||
from apps.wpm.models import Handover, WMaterial
|
||||
from apps.wpm.serializers import HandoverSerializer
|
||||
|
||||
|
||||
class HandoverSerializerQueryTests(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.dept = Dept.objects.create(name="合批查询测试车间")
|
||||
cls.user = User.objects.create_user(username="handover-query-user")
|
||||
cls.material = Material.objects.create(name="合批查询测试物料")
|
||||
cls.defect_b = Defect.objects.create(
|
||||
name="合批查询测试B类缺陷",
|
||||
cate=Defect.cate_list[0],
|
||||
okcate=Defect.DEFECT_OK_B,
|
||||
)
|
||||
cls.inventories = [
|
||||
WMaterial.objects.create(
|
||||
material=cls.material,
|
||||
batch=f"QUERY-{index}",
|
||||
count=1,
|
||||
state=WMaterial.WM_OK,
|
||||
defect=cls.defect_b if index == 2 else None,
|
||||
belong_dept=cls.dept,
|
||||
)
|
||||
for index in range(3)
|
||||
]
|
||||
|
||||
def test_handover_inventory_is_loaded_in_one_query(self):
|
||||
serializer = HandoverSerializer(data={
|
||||
"send_date": "2026-08-07",
|
||||
"send_user": self.user.id,
|
||||
"send_dept": self.dept.id,
|
||||
"recive_dept": self.dept.id,
|
||||
"handoverb": [
|
||||
{"wm": inventory.id, "count": 1}
|
||||
for inventory in self.inventories
|
||||
],
|
||||
"new_batch": "QUERY-MERGED",
|
||||
"clear_defect": True,
|
||||
"type": Handover.H_NORMAL,
|
||||
"mtype": Handover.H_MERGE,
|
||||
})
|
||||
|
||||
with CaptureQueriesContext(connection) as queries:
|
||||
self.assertTrue(serializer.is_valid(), serializer.errors)
|
||||
|
||||
inventory_queries = [
|
||||
query["sql"] for query in queries
|
||||
if 'FROM "wpm_wmaterial"' in query["sql"]
|
||||
]
|
||||
self.assertEqual(len(inventory_queries), 1, inventory_queries)
|
||||
Loading…
Reference in New Issue