diff --git a/mock/models.py b/mock/models.py index 87ba921..a84e587 100644 --- a/mock/models.py +++ b/mock/models.py @@ -64,6 +64,9 @@ class MockAPI(BaseTable): api_id = models.CharField(max_length=32, default=lambda: uuid.uuid4().hex, unique=True) enabled = models.BooleanField(default=True) + # 添加version字段用于乐观锁控制 + version = models.IntegerField(default=1) # 新增版本字段,默认值为1 + # TODO 改成many to many # followers: list = models.JSONField(null=True, blank=True, default=[], verbose_name="关注者") diff --git a/mock/serializers.py b/mock/serializers.py index c11894c..da9c8f6 100644 --- a/mock/serializers.py +++ b/mock/serializers.py @@ -25,6 +25,7 @@ class Meta: "request_method", "request_body", "response_text", + "version", "is_active", "api_id", "api_desc", diff --git a/mock/views.py b/mock/views.py index d73f30d..b91c96e 100644 --- a/mock/views.py +++ b/mock/views.py @@ -53,6 +53,37 @@ class MockAPIViewset(viewsets.ModelViewSet): filter_backends = [DjangoFilterBackend] filterset_class = MockAPIFilter + def update(self, request, *args, **kwargs): + partial = kwargs.pop('partial', False) + instance = self.get_object() + + # 获取传入的版本号 + incoming_version = request.data.get('version') + + # 如果数据库中的版本号比传入的版本号更大,阻止更新并返回错误 + if incoming_version is not None and instance.version > int(incoming_version): + return Response({ + 'status': 'error', + 'message': 'There is a newer version of this API already saved.' + }, status=status.HTTP_409_CONFLICT) + + serializer = self.get_serializer(instance, data=request.data, partial=partial) + serializer.is_valid(raise_exception=True) + + # 序列化器保存了实例,但我们还没有更新版本号 + self.perform_update(serializer) + + # 保存成功后,递增版本号并更新实例 + instance.version += 1 + instance.save(update_fields=['version']) # 只更新版本字段 + + if getattr(instance, '_prefetched_objects_cache', None): + # If 'prefetch_related' has been applied to a queryset, we need to + # forcibly invalidate the prefetch cache on the instance. + instance._prefetched_objects_cache = {} + + return Response(serializer.data) + class RequestObject: def __init__(self, request): self.method: str = request.method diff --git a/web/src/pages/mock_server/mock_api/index.vue b/web/src/pages/mock_server/mock_api/index.vue index 2cf4efe..4b7a153 100644 --- a/web/src/pages/mock_server/mock_api/index.vue +++ b/web/src/pages/mock_server/mock_api/index.vue @@ -259,6 +259,7 @@ def execute(req, resp): ], paginationSize: 10, + operationButtonType: 'button', searchForm: [ { type: 'input', diff --git a/web/src/pages/mock_server/mock_project/index.vue b/web/src/pages/mock_server/mock_project/index.vue index 84709f6..c536adc 100644 --- a/web/src/pages/mock_server/mock_project/index.vue +++ b/web/src/pages/mock_server/mock_project/index.vue @@ -10,6 +10,7 @@ export default { dataPath: "results", totalPath: "count", paginationSize: 10, + operationButtonType: 'button', canDelete: () => false, form: [ {