Browse Source

#27642 annotation_relations.py get, post, delete

pull/1384/head
descansodj@hotmail.it 3 years ago
parent
commit
95f9b38329
7 changed files with 115 additions and 19 deletions
  1. 5
      app/api/exceptions.py
  2. 7
      app/api/migrations/0009_annotations_relations_20210421_1445.py
  3. 29
      app/api/models.py
  4. 14
      app/api/serializers.py
  5. 15
      app/api/urls.py
  6. 1
      app/api/views/__init__.py
  7. 63
      app/api/views/annotation_relations.py

5
app/api/exceptions.py

@ -41,6 +41,11 @@ class LabelValidationError(APIException):
default_detail = 'You cannot create a label with same name or shortcut key.'
class AnnotationRelationValidationError(APIException):
status_code = status.HTTP_400_BAD_REQUEST
default_detail = 'You cannot create an annotation relation between the same annotation.'
class RelationTypesValidationError(APIException):
status_code = status.HTTP_400_BAD_REQUEST
default_detail = 'You cannot create a relation type with same name or color.'

7
app/api/migrations/0009_annotations_relations_20210421_1445.py

@ -26,9 +26,10 @@ class Migration(migrations.Migration):
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('annotation_id_1', models.IntegerField()),
('annotation_id_2', models.IntegerField()),
('type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.RelationTypes')),
('timestamp', models.DateTimeField(auto_now_add=True))
('type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.RelationTypes')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
('timestamp', models.DateTimeField(auto_now_add=True)),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='annotation_relations', to='api.Project'))
],
)
]

29
app/api/models.py

@ -265,20 +265,6 @@ class SequenceAnnotation(Annotation):
unique_together = ('document', 'user', 'label', 'start_offset', 'end_offset')
class AnnotationRelations(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True)
annotation_id_1 = models.IntegerField()
annotation_id_2 = models.IntegerField()
type = models.CharField(max_length=50)
def __str__(self):
return f"{self.annotation_id_1} - {self.annotation_id_2} - {type}"
class Meta:
unique_together = ('timestamp', 'user', 'annotation_id_1', 'annotation_id_2', 'type')
class RelationTypes(models.Model):
color = models.TextField()
name = models.TextField()
@ -291,6 +277,21 @@ class RelationTypes(models.Model):
unique_together = ('color', 'name')
class AnnotationRelations(models.Model):
annotation_id_1 = models.IntegerField()
annotation_id_2 = models.IntegerField()
type = models.ForeignKey(RelationTypes, related_name='annotation_relations', on_delete=models.CASCADE)
timestamp = models.DateTimeField()
user = models.ForeignKey(User, related_name='annotation_relations', on_delete=models.CASCADE)
project = models.ForeignKey(Project, related_name='annotation_relations', on_delete=models.CASCADE)
def __str__(self):
return self.__dict__.__str__()
class Meta:
unique_together = ('annotation_id_1', 'annotation_id_2', 'type', 'project')
class Seq2seqAnnotation(Annotation):
# Override AnnotationManager for custom functionality
objects = Seq2seqAnnotationManager()

14
app/api/serializers.py

@ -10,7 +10,7 @@ from .models import (AutoLabelingConfig, Comment, Document, DocumentAnnotation,
Label, Project, Role, RoleMapping, Seq2seqAnnotation,
Seq2seqProject, SequenceAnnotation,
SequenceLabelingProject, Speech2textAnnotation,
Speech2textProject, TextClassificationProject, RelationTypes)
Speech2textProject, TextClassificationProject, RelationTypes, AnnotationRelations)
class UserSerializer(serializers.ModelSerializer):
@ -286,4 +286,14 @@ class RelationTypesSerializer(serializers.ModelSerializer):
class Meta:
model = RelationTypes
fields = ('id', 'color', 'name')
fields = ('id', 'color', 'name')
class AnnotationRelationsSerializer(serializers.ModelSerializer):
def validate(self, attrs):
return super().validate(attrs)
class Meta:
model = AnnotationRelations
fields = ('id', 'annotation_id_1', 'annotation_id_2', 'type', 'user', 'timestamp')

15
app/api/urls.py

@ -38,6 +38,21 @@ urlpatterns_project = [
view=views.RelationTypesDetail.as_view(),
name='relation_type_detail'
),
path(
route='annotation_relations',
view=views.AnnotationRelationsList.as_view(),
name='relation_types_list'
),
path(
route='annotation_relation-upload',
view=views.AnnotationRelationsUploadAPI.as_view(),
name='annotation_relation-upload'
),
path(
route='annotation_relations/<int:annotation_relation_id>',
view=views.AnnotationRelationsDetail.as_view(),
name='annotation_relation_detail'
),
path(
route='docs',
view=views.DocumentList.as_view(),

1
app/api/views/__init__.py

@ -10,3 +10,4 @@ from .role import *
from .statistics import *
from .user import *
from .relation_types import *
from .annotation_relations import *

63
app/api/views/annotation_relations.py

@ -0,0 +1,63 @@
import json
import logging
from django.db import IntegrityError, transaction
from django.shortcuts import get_object_or_404
from rest_framework import generics, status
from rest_framework.exceptions import ParseError
from rest_framework.parsers import MultiPartParser
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from ..exceptions import AnnotationRelationValidationError
from ..models import AnnotationRelations, Project
from ..permissions import IsInProjectReadOnlyOrAdmin, IsProjectAdmin
from ..serializers import AnnotationRelationsSerializer
class AnnotationRelationsList(generics.ListCreateAPIView):
serializer_class = AnnotationRelationsSerializer
pagination_class = None
permission_classes = [IsAuthenticated & IsInProjectReadOnlyOrAdmin]
def get_queryset(self):
project = get_object_or_404(Project, pk=self.kwargs['project_id'])
return project.annotation_relations
def perform_create(self, serializer):
project = get_object_or_404(Project, pk=self.kwargs['project_id'])
serializer.save(project=project)
def delete(self, request, *args, **kwargs):
delete_ids = request.data['ids']
AnnotationRelations.objects.filter(pk__in=delete_ids).delete()
return Response(status=status.HTTP_204_NO_CONTENT)
class AnnotationRelationsDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = AnnotationRelations.objects.all()
serializer_class = AnnotationRelationsSerializer
lookup_url_kwarg = 'annotation_relation_id'
permission_classes = [IsAuthenticated & IsInProjectReadOnlyOrAdmin]
class AnnotationRelationsUploadAPI(APIView):
parser_classes = (MultiPartParser,)
permission_classes = [IsAuthenticated & IsProjectAdmin]
@transaction.atomic
def post(self, request, *args, **kwargs):
if 'file' not in request.data:
raise ParseError('Empty content')
project = get_object_or_404(Project, pk=kwargs['project_id'])
try:
annotation_relations = json.load(request.data)
serializer = AnnotationRelationsSerializer(data=annotation_relations, many=True)
serializer.is_valid(raise_exception=True)
serializer.save(project=project)
return Response(status=status.HTTP_201_CREATED)
except json.decoder.JSONDecodeError:
raise ParseError('The file format is invalid.')
except IntegrityError:
raise AnnotationRelationValidationError
Loading…
Cancel
Save