This commit is contained in:
zty 2025-09-12 14:18:57 +08:00
commit aff39f3e31
5 changed files with 64 additions and 65 deletions

View File

@ -9,7 +9,6 @@ from django.utils.timezone import now
from user_agents import parse
import logging
from rest_framework.response import Response
from django.db import transaction
from rest_framework.exceptions import ParseError, ValidationError
from apps.utils.errors import PKS_ERROR
from rest_framework.generics import get_object_or_404
@ -19,6 +18,7 @@ from apps.utils.serializers import PkSerializer
from rest_framework.decorators import action
from apps.utils.serializers import ComplexSerializer
from django.db.models import F
from django.db import transaction
# 实例化myLogger
myLogger = logging.getLogger('log')
@ -81,7 +81,8 @@ class BulkCreateModelMixin(CreateModelMixin):
def after_bulk_create(self, objs):
pass
@transaction.atomic
def create(self, request, *args, **kwargs):
"""创建(支持批量)
@ -91,10 +92,9 @@ class BulkCreateModelMixin(CreateModelMixin):
many = False
if isinstance(rdata, list):
many = True
with transaction.atomic():
sr = self.get_serializer(data=rdata, many=many)
sr.is_valid(raise_exception=True)
self.perform_create(sr)
sr = self.get_serializer(data=rdata, many=many)
sr.is_valid(raise_exception=True)
self.perform_create(sr)
if many:
self.after_bulk_create(sr.data)
return Response(sr.data, status=201)
@ -105,6 +105,7 @@ class BulkUpdateModelMixin(UpdateModelMixin):
def after_bulk_update(self, objs):
pass
@transaction.atomic
def partial_update(self, request, *args, **kwargs):
"""部分更新(支持批量)
@ -113,6 +114,7 @@ class BulkUpdateModelMixin(UpdateModelMixin):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
@transaction.atomic
def update(self, request, *args, **kwargs):
"""更新(支持批量)
@ -124,16 +126,15 @@ class BulkUpdateModelMixin(UpdateModelMixin):
queryset = self.filter_queryset(self.get_queryset())
objs = []
if isinstance(request.data, list):
with transaction.atomic():
for ind, item in enumerate(request.data):
obj = get_object_or_404(queryset, id=item['id'])
sr = self.get_serializer(obj, data=item, partial=partial)
if not sr.is_valid():
err_dict = { f'{ind+1}': sr.errors}
raise ValidationError(err_dict)
self.perform_update(sr) # 用自带的更新,可能需要做其他操作
objs.append(sr.data)
self.after_bulk_update(objs)
for ind, item in enumerate(request.data):
obj = get_object_or_404(queryset, id=item['id'])
sr = self.get_serializer(obj, data=item, partial=partial)
if not sr.is_valid():
err_dict = { f'{ind+1}': sr.errors}
raise ValidationError(err_dict)
self.perform_update(sr) # 用自带的更新,可能需要做其他操作
objs.append(sr.data)
self.after_bulk_update(objs)
else:
raise ParseError('提交数据非列表')
return Response(objs)
@ -148,6 +149,7 @@ class BulkUpdateModelMixin(UpdateModelMixin):
class BulkDestroyModelMixin(DestroyModelMixin):
@swagger_auto_schema(request_body=PkSerializer)
@transaction.atomic
def destroy(self, request, *args, **kwargs):
"""删除(支持批量)

View File

@ -1,6 +1,6 @@
from django.core.cache import cache
from django.http import StreamingHttpResponse
from django.http import StreamingHttpResponse, Http404
from rest_framework.decorators import action
from rest_framework.exceptions import ParseError
from rest_framework.mixins import RetrieveModelMixin
@ -18,7 +18,8 @@ from apps.utils.serializers import ComplexSerializer
from rest_framework.throttling import UserRateThrottle
from drf_yasg.utils import swagger_auto_schema
import json
from django.db import connection
from django.core.exceptions import ObjectDoesNotExist
class CustomGenericViewSet(MyLoggingMixin, GenericViewSet):
"""
@ -89,6 +90,34 @@ class CustomGenericViewSet(MyLoggingMixin, GenericViewSet):
elif hash_v_e:
return Response(hash_v_e)
def get_object(self, force_lock=False):
"""
智能加锁的get_object
- 只读请求普通查询
- 非只读请求且在事务中加锁查询
- 非只读请求但不在事务中普通查询带警告
"""
# 只读方法列表
read_only_methods = ['GET', 'HEAD', 'OPTIONS']
if self.request.method not in read_only_methods and connection.in_atomic_block:
if force_lock:
raise ParseError("当前操作需要在事务中进行,请使用事务装饰器")
# 非只读请求且在事务中:加锁查询
queryset = self.filter_queryset(self.get_queryset())
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
try:
obj = queryset.select_for_update().get(**filter_kwargs)
self.check_object_permissions(self.request, obj)
return obj
except ObjectDoesNotExist:
raise Http404
else:
# 其他情况:普通查询
return super().get_object()
def get_serializer_class(self):
action_serializer_name = f"{self.action}_serializer_class"
action_serializer_class = getattr(self, action_serializer_name, None)
@ -193,5 +222,4 @@ class CustomModelViewSet(BulkCreateModelMixin, BulkUpdateModelMixin, CustomListM
CustomRetrieveModelMixin, BulkDestroyModelMixin, ComplexQueryMixin, CustomGenericViewSet):
"""
增强的ModelViewSet
"""
pass
"""

View File

@ -738,7 +738,6 @@ class BatchSt(BaseModel):
# return ins, True
@classmethod
@transaction.atomic
def init_dag(cls, batch:str):
"""
更新批次数据关系链(初步)

View File

@ -885,7 +885,6 @@ class MlogbwCreateUpdateSerializer(CustomModelSerializer):
ftest_sr.update(instance=ftest, validated_data=ftest_data)
return mlogbw
@transaction.atomic
def create(self, validated_data):
wpr: Wpr = validated_data.get("wpr", None)
if wpr:
@ -898,7 +897,6 @@ class MlogbwCreateUpdateSerializer(CustomModelSerializer):
mlogbw = self.save_ftest(mlogbw, ftest_data)
return mlogbw
@transaction.atomic
def update(self, instance, validated_data):
validated_data.pop("mlogb")
ftest_data = validated_data.pop("ftest", None)
@ -1078,7 +1076,6 @@ class MlogbOutUpdateSerializer(CustomModelSerializer):
# else:
# raise ParseError("mlogbdefect仅支持批次件")
# return ins
@transaction.atomic
def update(self, instance, validated_data):
mlogbdefect = validated_data.pop("mlogbdefect", None)
with transaction.atomic():

View File

@ -37,14 +37,12 @@ from django.db.models import Q
from apps.utils.tools import convert_ordereddict, update_dict
from django.db.models import Count
from datetime import datetime, timedelta
from apps.utils.lock import lock_model_record_d_method
from apps.em.models import Equipment
from django.db.models import Prefetch
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
# Create your views here.
@ -155,7 +153,6 @@ class WMaterialViewSet(ListModelMixin, CustomGenericViewSet):
return queryset.exclude(state=WMaterial.WM_SCRAP)
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=DeptBatchSerializer)
@transaction.atomic
def batchs(self, request):
"""获取车间的批次号(废弃)
@ -282,7 +279,6 @@ class MlogViewSet(CustomModelViewSet):
item["mlogbw_number_list"] = wpr_dict.get(item["id"], None)
return data
@lock_model_record_d_method(Mlog)
def perform_destroy(self, instance):
if instance.submit_time is not None:
raise ParseError('日志已提交不可变动')
@ -295,7 +291,6 @@ class MlogViewSet(CustomModelViewSet):
instance.delete()
Ftest.objects.filter(id__in=ftestIds).delete()
@transaction.atomic
def perform_update(self, serializer):
ins = serializer.instance
if ins.ticket and ins.ticket.state != State.STATE_TYPE_START:
@ -318,7 +313,10 @@ class MlogViewSet(CustomModelViewSet):
ins = sr.save()
return Response(MlogSerializer(ins).data)
@action(methods=['post'], detail=True, perms_map={'post': 'mlog.update'}, serializer_class=MlogChangeSerializer)
@action(methods=['post'], detail=True,
perms_map={'post': 'mlog.update'},
serializer_class=MlogChangeSerializer)
@transaction.atomic
def change(self, request, *args, **kwargs):
"""修改日志
@ -334,7 +332,9 @@ class MlogViewSet(CustomModelViewSet):
sr.save()
return Response(MlogSerializer(ins).data)
@action(methods=['post'], detail=True, perms_map={'post': 'mlog.submit'}, serializer_class=Serializer)
@action(methods=['post'], detail=True, perms_map={'post': 'mlog.submit'},
serializer_class=Serializer)
@transaction.atomic
def submit(self, request, *args, **kwargs):
"""日志提交(变动车间库存)
@ -349,20 +349,12 @@ class MlogViewSet(CustomModelViewSet):
if p.mlog_need_ticket:
raise ParseError('该日志需要审批!')
mlog_submit_validate(ins)
with transaction.atomic():
updated_count = Mlog.objects.filter(id=ins.id, submit_time__isnull=True).update(
submit_time=now, submit_user=request.user, update_by=request.user)
if updated_count == 1:
mlog_submit(ins, self.request.user, now)
else:
raise ParseError('记录正在处理中,请稍后再试')
vdata_new = MlogSerializer(ins).data
# create_auditlog('submit', ins, vdata_new,
# vdata_old, now, self.request.user)
mlog_submit(ins, self.request.user, now)
vdata_new = MlogSerializer(ins).data
return Response(vdata_new)
@action(methods=['post'], detail=True, perms_map={'post': 'mlog.submit'}, serializer_class=MlogRevertSerializer)
@transaction.atomic
def revert(self, request, *args, **kwargs):
"""撤回日志提交
@ -377,20 +369,10 @@ class MlogViewSet(CustomModelViewSet):
if user != ins.submit_user:
raise ParseError('非提交人不可撤销!')
now = timezone.now()
with transaction.atomic():
updated_count = Mlog.objects.filter(id=ins.id, submit_time__isnull=False).update(
submit_time=None, update_time=now, submit_user=None, update_by=request.user)
if updated_count == 1:
mlog_revert(ins, user, now)
else:
raise ParseError('记录正在处理中,请稍后再试')
# create_auditlog('revert', ins, {}, {}, now, user,
# request.data.get('change_reason', ''))
mlog_revert(ins, user, now)
return Response(MlogSerializer(instance=ins).data)
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=MlogRelatedSerializer)
@transaction.atomic
def related_first(self, request, *args, **kwargs):
"""获取相关任务的第一道工序日志
@ -508,8 +490,7 @@ class HandoverViewSet(CustomModelViewSet):
'material__number', 'material__specification', 'batch', 'material__model', 'b_handover__batch', "new_batch", "wm__batch"]
prefetch_related_fields = ["b_handover"]
@lock_model_record_d_method(Handover)
def perform_destroy(self, instance:Handover):
def perform_destroy(self, instance):
user = self.request.user
if instance.submit_time is not None:
raise ParseError('该交接记录已提交不可删除')
@ -520,9 +501,8 @@ class HandoverViewSet(CustomModelViewSet):
ticket.delete()
instance.delete()
@transaction.atomic
def perform_update(self, serializer):
ins:Handover = self.get_object()
ins:Handover = serializer.instance
if ins.submit_time is not None:
raise ParseError('该交接记录已提交!')
ticket:Ticket = ins.ticket
@ -580,7 +560,6 @@ class HandoverViewSet(CustomModelViewSet):
return Response()
@action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=HandoverMgroupSerializer)
@transaction.atomic
def mgroups(self, request, *args, **kwargs):
"""获取可交接到的工段
@ -708,7 +687,6 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust
serializer_class = MlogbInSerializer
update_serializer_class = MlogbInUpdateSerializer
@transaction.atomic
def perform_destroy(self, instance):
ins: Mlogb = instance
if ins.mlog.submit_time is not None:
@ -716,7 +694,6 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust
ins.delete()
ins.mlog.cal_mlog_count_from_mlogb()
@transaction.atomic
def perform_update(self, serializer):
ins:Mlogb = serializer.save()
ins.mlog.cal_mlog_count_from_mlogb()
@ -883,7 +860,7 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust
raise ParseError("不支持生成产出物料!")
mlog.cal_mlog_count_from_mlogb()
@transaction.atomic
def perform_create(self, serializer):
mlogbin: Mlogb = serializer.save()
MlogbInViewSet.p_create_after(mlogbin)
@ -925,7 +902,6 @@ class MlogbOutViewSet(UpdateModelMixin, CustomGenericViewSet):
queryset = Mlogb.objects.filter(material_out__isnull=False)
serializer_class = MlogbOutUpdateSerializer
@transaction.atomic
def perform_update(self, serializer):
material_out = serializer.validated_data.get('material_out')
if material_out and material_out.tracking == Material.MA_TRACKING_SINGLE:
@ -985,7 +961,6 @@ class MlogbwViewSet(CustomModelViewSet):
# raise ParseError('请指定所属消耗/产出明细')
# return super().filter_queryset(queryset)
@transaction.atomic
def perform_create(self, serializer):
ins:Mlogbw = serializer.save()
mlog:Mlog = None
@ -1061,7 +1036,6 @@ class MlogbwViewSet(CustomModelViewSet):
raise ParseError("该个号不可产生该批")
mlog.cal_mlog_count_from_mlogb()
@transaction.atomic
def perform_update(self, serializer):
mlogbw = serializer.save()
if isinstance(mlogbw, list):
@ -1079,7 +1053,6 @@ class MlogbwViewSet(CustomModelViewSet):
mlog = mlogb.mlog
mlog.cal_mlog_count_from_mlogb()
@transaction.atomic
def perform_destroy(self, instance:Mlogbw):
mlogb:Mlogb = instance.mlogb
if mlogb.material_out is not None and instance.wpr is not None: