feat: wpm优化事务和悲观锁

This commit is contained in:
caoqianming 2025-09-15 09:41:20 +08:00
parent aa80c1b00a
commit 00d0b1ea00
1 changed files with 23 additions and 23 deletions

View File

@ -3,7 +3,6 @@ import math
from django.db import transaction from django.db import transaction
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.exceptions import ParseError from rest_framework.exceptions import ParseError
from rest_framework.mixins import DestroyModelMixin, ListModelMixin, UpdateModelMixin, CreateModelMixin
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.serializers import Serializer from rest_framework.serializers import Serializer
from django.db.models import Sum from django.db.models import Sum
@ -12,7 +11,7 @@ from apps.system.models import User
from apps.mtm.models import Material, Process, Route, Mgroup, RoutePack, RouteMat from apps.mtm.models import Material, Process, Route, Mgroup, RoutePack, RouteMat
from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
from apps.utils.mixins import CustomListModelMixin, BulkCreateModelMixin, ComplexQueryMixin from apps.utils.mixins import CustomListModelMixin, BulkCreateModelMixin, ComplexQueryMixin, BulkDestroyModelMixin, BulkUpdateModelMixin
from .filters import StLogFilter, SfLogFilter, WMaterialFilter, MlogFilter, HandoverFilter, MlogbFilter, BatchStFilter, MlogbwFilter from .filters import StLogFilter, SfLogFilter, WMaterialFilter, MlogFilter, HandoverFilter, MlogbFilter, BatchStFilter, MlogbwFilter
from .models import (SfLog, SfLogExp, StLog, WMaterial, Mlog, Handover, Mlogb, from .models import (SfLog, SfLogExp, StLog, WMaterial, Mlog, Handover, Mlogb,
@ -41,6 +40,7 @@ from apps.em.models import Equipment
from django.db.models import Prefetch from django.db.models import Prefetch
from drf_yasg.utils import swagger_auto_schema from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi from drf_yasg import openapi
from django.db import connection
# Create your views here. # Create your views here.
@ -68,7 +68,7 @@ class StLogViewSet(CustomModelViewSet):
return super().destroy(request, *args, **kwargs) return super().destroy(request, *args, **kwargs)
class SfLogViewSet(UpdateModelMixin, CustomListModelMixin, DestroyModelMixin, CustomGenericViewSet): class SfLogViewSet(BulkUpdateModelMixin, CustomListModelMixin, BulkDestroyModelMixin, CustomGenericViewSet):
""" """
list:值班记录 list:值班记录
@ -118,7 +118,7 @@ class SfLogViewSet(UpdateModelMixin, CustomListModelMixin, DestroyModelMixin, Cu
return Response(sr.data) return Response(sr.data)
class SfLogExpViewSet(ListModelMixin, UpdateModelMixin, CustomGenericViewSet): class SfLogExpViewSet(CustomListModelMixin, BulkUpdateModelMixin, CustomGenericViewSet):
""" """
list:异常值班处理 list:异常值班处理
@ -131,7 +131,7 @@ class SfLogExpViewSet(ListModelMixin, UpdateModelMixin, CustomGenericViewSet):
filterset_fields = ['sflog', 'stlog'] filterset_fields = ['sflog', 'stlog']
class WMaterialViewSet(ListModelMixin, CustomGenericViewSet): class WMaterialViewSet(CustomListModelMixin, CustomGenericViewSet):
""" """
list: 车间库存 list: 车间库存
@ -208,9 +208,12 @@ class MlogViewSet(CustomModelViewSet):
@classmethod @classmethod
def lock_and_check_can_update(cls, mlog:Mlog): def lock_and_check_can_update(cls, mlog:Mlog):
# mlog_lock:Mlog = Mlog.objects.select_for_update().get(id=mlog.id) if not connection.in_atomic_block:
raise ParseError("请在事务中调用该方法")
mlog_lock:Mlog = Mlog.objects.select_for_update().get(id=mlog.id)
if mlog.submit_time is not None: if mlog.submit_time is not None:
raise ParseError("该记录已提交无法更改") raise ParseError("该记录已提交无法更改")
return mlog_lock
def get_serializer_class(self): def get_serializer_class(self):
@ -688,7 +691,7 @@ class MlogbViewSet(CustomListModelMixin, CustomGenericViewSet):
ordering = ["create_time"] ordering = ["create_time"]
class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, CustomGenericViewSet): class MlogbInViewSet(BulkCreateModelMixin, BulkUpdateModelMixin, BulkDestroyModelMixin, CustomGenericViewSet):
perms_map = {'post': 'mlog.update', 'delete': 'mlog.update', 'put': 'mlog.update'} perms_map = {'post': 'mlog.update', 'delete': 'mlog.update', 'put': 'mlog.update'}
queryset = Mlogb.objects.filter(material_in__isnull=False) queryset = Mlogb.objects.filter(material_in__isnull=False)
serializer_class = MlogbInSerializer serializer_class = MlogbInSerializer
@ -696,15 +699,15 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust
def perform_destroy(self, instance): def perform_destroy(self, instance):
ins: Mlogb = instance ins: Mlogb = instance
MlogViewSet.lock_and_check_can_update(ins.mlog) mlog = MlogViewSet.lock_and_check_can_update(ins.mlog)
ins.delete() ins.delete()
ins.mlog.cal_mlog_count_from_mlogb() mlog.cal_mlog_count_from_mlogb()
def perform_update(self, serializer): def perform_update(self, serializer):
ins:Mlogb = serializer.instance ins:Mlogb = serializer.instance
MlogViewSet.lock_and_check_can_update(ins.mlog) mlog = MlogViewSet.lock_and_check_can_update(ins.mlog)
ins:Mlogb = serializer.save() ins:Mlogb = serializer.save()
ins.mlog.cal_mlog_count_from_mlogb() mlog.cal_mlog_count_from_mlogb()
@classmethod @classmethod
def p_create_after(cls, mlogbin:Mlogb): def p_create_after(cls, mlogbin:Mlogb):
@ -906,19 +909,19 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust
except Exception as e: except Exception as e:
raise ParseError(f"个号生成错误: {e}") raise ParseError(f"个号生成错误: {e}")
class MlogbOutViewSet(UpdateModelMixin, CustomGenericViewSet): class MlogbOutViewSet(BulkUpdateModelMixin, CustomGenericViewSet):
perms_map = {"put": "mlog.update"} perms_map = {"put": "mlog.update"}
queryset = Mlogb.objects.filter(material_out__isnull=False) queryset = Mlogb.objects.filter(material_out__isnull=False)
serializer_class = MlogbOutUpdateSerializer serializer_class = MlogbOutUpdateSerializer
def perform_update(self, serializer): def perform_update(self, serializer):
ins:Mlogb = serializer.instance ins:Mlogb = serializer.instance
MlogViewSet.lock_and_check_can_update(ins.mlog) mlog = MlogViewSet.lock_and_check_can_update(ins.mlog)
material_out = serializer.validated_data.get('material_out') material_out = serializer.validated_data.get('material_out')
if material_out and material_out.tracking == Material.MA_TRACKING_SINGLE: if material_out and material_out.tracking == Material.MA_TRACKING_SINGLE:
raise ParseError("单件产品不支持直接修改") raise ParseError("单件产品不支持直接修改")
ins:Mlogb = serializer.save() ins:Mlogb = serializer.save()
ins.mlog.cal_mlog_count_from_mlogb() mlog.cal_mlog_count_from_mlogb()
class FmlogViewSet(CustomModelViewSet): class FmlogViewSet(CustomModelViewSet):
@ -943,7 +946,7 @@ class FmlogViewSet(CustomModelViewSet):
ins.save() ins.save()
return Response() return Response()
class BatchStViewSet(ListModelMixin, ComplexQueryMixin, CustomGenericViewSet): class BatchStViewSet(CustomListModelMixin, ComplexQueryMixin, CustomGenericViewSet):
""" """
list: 批次统计数据 list: 批次统计数据
@ -1057,7 +1060,7 @@ class MlogbwViewSet(CustomModelViewSet):
pass pass
else: else:
mlog = mlogbw.mlogb.mlog mlog = mlogbw.mlogb.mlog
MlogViewSet.lock_and_check_can_update(mlog) mlog = MlogViewSet.lock_and_check_can_update(mlog)
Mlogbw.cal_count_notok(mlogbw.mlogb) Mlogbw.cal_count_notok(mlogbw.mlogb)
mlog.cal_mlog_count_from_mlogb() mlog.cal_mlog_count_from_mlogb()
@ -1066,15 +1069,13 @@ class MlogbwViewSet(CustomModelViewSet):
mlogbIds = list(set([obj["mlogb"] for obj in objs])) mlogbIds = list(set([obj["mlogb"] for obj in objs]))
for mlogbId in mlogbIds: for mlogbId in mlogbIds:
mlogb = Mlogb.objects.get(id=mlogbId) mlogb = Mlogb.objects.get(id=mlogbId)
mlog = mlogb.mlog mlog = MlogViewSet.lock_and_check_can_update(mlogb.mlog)
MlogViewSet.lock_and_check_can_update(mlog)
Mlogbw.cal_count_notok(mlogb) Mlogbw.cal_count_notok(mlogb)
mlog.cal_mlog_count_from_mlogb() mlog.cal_mlog_count_from_mlogb()
def perform_destroy(self, instance:Mlogbw): def perform_destroy(self, instance:Mlogbw):
mlogb:Mlogb = instance.mlogb mlogb:Mlogb = instance.mlogb
MlogViewSet.lock_and_check_can_update(mlogb.mlog) mlog = MlogViewSet.lock_and_check_can_update(mlogb.mlog)
if mlogb.material_out is not None and instance.wpr is not None: if mlogb.material_out is not None and instance.wpr is not None:
raise ParseError("不能删除该产出明细") raise ParseError("不能删除该产出明细")
@ -1099,7 +1100,6 @@ class MlogbwViewSet(CustomModelViewSet):
for mlogb in mlogb_qs: for mlogb in mlogb_qs:
Mlogbw.cal_count_notok(mlogb) Mlogbw.cal_count_notok(mlogb)
mlog = mlogb.mlog
mlog.cal_mlog_count_from_mlogb() mlog.cal_mlog_count_from_mlogb()
@action(methods=['post'], detail=False, perms_map={'post': 'mlog.update'}, serializer_class=MlogbwStartTestSerializer) @action(methods=['post'], detail=False, perms_map={'post': 'mlog.update'}, serializer_class=MlogbwStartTestSerializer)
@ -1110,7 +1110,7 @@ class MlogbwViewSet(CustomModelViewSet):
sr.save() sr.save()
return Response() return Response()
class MlogUserViewSet(BulkCreateModelMixin, ListModelMixin, DestroyModelMixin, CustomGenericViewSet): class MlogUserViewSet(BulkCreateModelMixin, CustomListModelMixin, BulkDestroyModelMixin, CustomGenericViewSet):
perms_map = {"get": "*", "post": "mlog.update", "delete": "mlog.update"} perms_map = {"get": "*", "post": "mlog.update", "delete": "mlog.update"}
queryset = MlogUser.objects.all() queryset = MlogUser.objects.all()
serializer_class = MlogUserSerializer serializer_class = MlogUserSerializer
@ -1129,7 +1129,7 @@ class MlogUserViewSet(BulkCreateModelMixin, ListModelMixin, DestroyModelMixin, C
return super().perform_destroy(instance) return super().perform_destroy(instance)
class BatchLogViewSet(ListModelMixin, CustomGenericViewSet): class BatchLogViewSet(CustomListModelMixin, CustomGenericViewSet):
perms_map = {"get": "*"} perms_map = {"get": "*"}
queryset = BatchLog.objects.all() queryset = BatchLog.objects.all()
serializer_class = BatchLogSerializer serializer_class = BatchLogSerializer