未验证 提交 14dc68e7 编写于 作者: N Nikita Manovich 提交者: GitHub

Optimized jobs request (#5962)

上级 c5156f4e
......@@ -43,6 +43,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Escaping in the `filter` parameter in generated URLs
(<https://github.com/opencv/cvat/issues/5566>)
- Rotation property lost during saving a mutable attribute (<https://github.com/opencv/cvat/pull/5968>)
- Optimized /api/jobs request (<https://github.com/opencv/cvat/pull/5962>)
- Server micro version support check in SDK/CLI (<https://github.com/opencv/cvat/pull/5991>)
- \[SDK\] Compatibility with upcoming urllib 2.1.0
(<https://github.com/opencv/cvat/pull/6002>)
......
......@@ -136,12 +136,6 @@ class _CollectionSummarySerializer(serializers.Serializer):
def get_attribute(self, instance):
return instance
class LabelsSummarySerializer(_CollectionSummarySerializer):
def __init__(self, *, model=models.Label, url_filter_key, source='get_labels', **kwargs):
super().__init__(model=model, url_filter_key=url_filter_key, source=source, **kwargs)
class JobsSummarySerializer(_CollectionSummarySerializer):
completed = serializers.IntegerField(source='completed_jobs_count', default=0)
......@@ -156,10 +150,36 @@ class TasksSummarySerializer(_CollectionSummarySerializer):
class CommentsSummarySerializer(_CollectionSummarySerializer):
pass
class BasicSummarySerializer(serializers.Serializer):
url = serializers.URLField(read_only=True)
count = serializers.IntegerField(read_only=True)
class IssuesSummarySerializer(_CollectionSummarySerializer):
pass
def to_representation(self, instance):
request = self.context.get('request')
if not request:
return None
return {
'url': self.get_url(request, instance),
'count': self.get_count(instance)
}
class LabelsSummarySerializer(BasicSummarySerializer):
def get_url(self, request, instance):
filter_key = instance.__class__.__name__.lower() + '_id'
return reverse('label-list', request=request,
query_params={ filter_key: instance.id })
def get_count(self, instance):
return getattr(instance, 'task_labels_count', 0) + getattr(instance, 'proj_labels_count', 0)
class IssuesSummarySerializer(BasicSummarySerializer):
def get_url(self, request, instance):
return reverse('issue-list', request=request,
query_params={ 'job_id': instance.id })
def get_count(self, instance):
return getattr(instance, 'issues__count', 0)
class BasicUserSerializer(serializers.ModelSerializer):
def validate(self, attrs):
......@@ -532,15 +552,16 @@ class JobReadSerializer(serializers.ModelSerializer):
mode = serializers.ReadOnlyField(source='segment.task.mode')
bug_tracker = serializers.CharField(max_length=2000, source='get_bug_tracker',
allow_null=True, read_only=True)
labels = LabelsSummarySerializer(url_filter_key='job_id')
issues = IssuesSummarySerializer(models.Issue, url_filter_key='job_id')
labels = LabelsSummarySerializer(source='*')
issues = IssuesSummarySerializer(source='*')
class Meta:
model = models.Job
fields = ('url', 'id', 'task_id', 'project_id', 'assignee',
'dimension', 'bug_tracker', 'status', 'stage', 'state', 'mode',
'start_frame', 'stop_frame', 'data_chunk_size', 'data_compressed_chunk_type',
'updated_date', 'issues', 'labels')
'updated_date', 'issues', 'labels'
)
read_only_fields = fields
class JobWriteSerializer(serializers.ModelSerializer):
......@@ -848,7 +869,7 @@ class TaskReadSerializer(serializers.ModelSerializer):
target_storage = StorageSerializer(required=False, allow_null=True)
source_storage = StorageSerializer(required=False, allow_null=True)
jobs = JobsSummarySerializer(url_filter_key='task_id', source='segment_set')
labels = LabelsSummarySerializer(url_filter_key='task_id')
labels = LabelsSummarySerializer(source='*')
class Meta:
model = models.Task
......@@ -998,6 +1019,10 @@ class TaskWriteSerializer(WriteOnceMixin, serializers.ModelSerializer):
_update_related_storages(instance, validated_data)
instance.save()
instance.task_labels_count = instance.label_set.filter(
parent__isnull=True).count()
instance.proj_labels_count = instance.project.label_set.filter(
parent__isnull=True).count() if instance.project else 0
return instance
def validate(self, attrs):
......@@ -1059,7 +1084,7 @@ class ProjectReadSerializer(serializers.ModelSerializer):
target_storage = StorageSerializer(required=False, allow_null=True, read_only=True)
source_storage = StorageSerializer(required=False, allow_null=True, read_only=True)
tasks = TasksSummarySerializer(models.Task, url_filter_key='project_id')
labels = LabelsSummarySerializer(url_filter_key='project_id')
labels = LabelsSummarySerializer(source='*')
class Meta:
model = models.Project
......@@ -1137,6 +1162,9 @@ class ProjectWriteSerializer(serializers.ModelSerializer):
_update_related_storages(instance, validated_data)
instance.save()
instance.proj_labels_count = instance.label_set.filter(
parent__isnull=True).count()
return instance
class AboutSerializer(serializers.Serializer):
......
......@@ -21,6 +21,7 @@ from django.db import IntegrityError
from django.http import HttpResponse, HttpResponseNotFound, HttpResponseBadRequest
from django.utils import timezone
import django.db.models as dj_models
from django.db.models import Count, Q
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import (
......@@ -229,6 +230,9 @@ class ProjectViewSet(viewsets.GenericViewSet, mixins.ListModelMixin,
).prefetch_related(
'tasks', 'label_set__sublabels__attributespec_set',
'label_set__attributespec_set'
).annotate(
proj_labels_count=Count('label',
filter=Q(label__parent__isnull=True), distinct=True)
).all()
# NOTE: The search_fields attribute should be a list of names of text
......@@ -667,7 +671,11 @@ class TaskViewSet(viewsets.GenericViewSet, mixins.ListModelMixin,
completed_jobs_count=dj_models.Count(
'segment__job',
filter=dj_models.Q(segment__job__state=models.StateChoice.COMPLETED.value)
)
),
task_labels_count=Count('label',
filter=Q(label__parent__isnull=True), distinct=True),
proj_labels_count=Count('project__label',
filter=Q(project__label__parent__isnull=True), distinct=True)
).all()
lookup_fields = {
......@@ -1234,12 +1242,14 @@ class TaskViewSet(viewsets.GenericViewSet, mixins.ListModelMixin,
class JobViewSet(viewsets.GenericViewSet, mixins.ListModelMixin,
mixins.RetrieveModelMixin, PartialUpdateModelMixin, UploadMixin, AnnotationMixin
):
queryset = Job.objects.select_related('segment__task__data').prefetch_related(
'segment__task__label_set', 'segment__task__project__label_set',
'segment__task__label_set__sublabels__attributespec_set',
'segment__task__project__label_set__sublabels__attributespec_set',
'segment__task__label_set__attributespec_set',
'segment__task__project__label_set__attributespec_set'
queryset = Job.objects.select_related('assignee', 'segment__task__data',
'segment__task__project'
).annotate(
Count('issues', distinct=True),
task_labels_count=Count('segment__task__label',
filter=Q(segment__task__label__parent__isnull=True), distinct=True),
proj_labels_count=Count('segment__task__project__label',
filter=Q(segment__task__project__label__parent__isnull=True), distinct=True)
).all()
iam_organization_field = 'segment__task__organization'
......
......@@ -7123,13 +7123,13 @@ components:
IssuesSummary:
type: object
properties:
count:
type: integer
default: 0
url:
type: string
format: uri
readOnly: true
count:
type: integer
readOnly: true
JobAnnotationsUpdateRequest:
oneOf:
- $ref: '#/components/schemas/LabeledDataRequest'
......@@ -7563,13 +7563,13 @@ components:
LabelsSummary:
type: object
properties:
count:
type: integer
default: 0
url:
type: string
format: uri
readOnly: true
count:
type: integer
readOnly: true
LocationEnum:
enum:
- cloud_storage
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册