diff --git a/backend/api/migrations/0018_alter_label_background_color.py b/backend/api/migrations/0018_alter_label_background_color.py index ca7ec81e..3cf13c2c 100644 --- a/backend/api/migrations/0018_alter_label_background_color.py +++ b/backend/api/migrations/0018_alter_label_background_color.py @@ -1,8 +1,9 @@ # Generated by Django 3.2.8 on 2021-11-17 05:56 -import api.models from django.db import migrations, models +from label_types.models import generate_random_hex_color + class Migration(migrations.Migration): @@ -14,6 +15,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='label', name='background_color', - field=models.CharField(default=api.models.generate_random_hex_color, max_length=7), + field=models.CharField(default=generate_random_hex_color, max_length=7), ), ] diff --git a/backend/api/migrations/0020_auto_20211221_1415.py b/backend/api/migrations/0020_auto_20211221_1415.py index b0c1bcc5..5561816b 100644 --- a/backend/api/migrations/0020_auto_20211221_1415.py +++ b/backend/api/migrations/0020_auto_20211221_1415.py @@ -1,9 +1,10 @@ # Generated by Django 3.2.8 on 2021-12-21 14:15 -import api.models from django.db import migrations, models import django.db.models.deletion +from label_types.models import generate_random_hex_color + class Migration(migrations.Migration): @@ -19,7 +20,7 @@ class Migration(migrations.Migration): ('text', models.CharField(db_index=True, max_length=100)), ('prefix_key', models.CharField(blank=True, choices=[('ctrl', 'ctrl'), ('shift', 'shift'), ('ctrl shift', 'ctrl shift')], max_length=10, null=True)), ('suffix_key', models.CharField(blank=True, choices=[('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'), ('7', '7'), ('8', '8'), ('9', '9'), ('a', 'a'), ('b', 'b'), ('c', 'c'), ('d', 'd'), ('e', 'e'), ('f', 'f'), ('g', 'g'), ('h', 'h'), ('i', 'i'), ('j', 'j'), ('k', 'k'), ('l', 'l'), ('m', 'm'), ('n', 'n'), ('o', 'o'), ('p', 'p'), ('q', 'q'), ('r', 'r'), ('s', 's'), ('t', 't'), ('u', 'u'), ('v', 'v'), ('w', 'w'), ('x', 'x'), ('y', 'y'), ('z', 'z')], max_length=1, null=True)), - ('background_color', models.CharField(default=api.models.generate_random_hex_color, max_length=7)), + ('background_color', models.CharField(default=generate_random_hex_color, max_length=7)), ('text_color', models.CharField(default='#ffffff', max_length=7)), ('created_at', models.DateTimeField(auto_now_add=True, db_index=True)), ('updated_at', models.DateTimeField(auto_now=True)), @@ -36,7 +37,7 @@ class Migration(migrations.Migration): ('text', models.CharField(db_index=True, max_length=100)), ('prefix_key', models.CharField(blank=True, choices=[('ctrl', 'ctrl'), ('shift', 'shift'), ('ctrl shift', 'ctrl shift')], max_length=10, null=True)), ('suffix_key', models.CharField(blank=True, choices=[('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'), ('7', '7'), ('8', '8'), ('9', '9'), ('a', 'a'), ('b', 'b'), ('c', 'c'), ('d', 'd'), ('e', 'e'), ('f', 'f'), ('g', 'g'), ('h', 'h'), ('i', 'i'), ('j', 'j'), ('k', 'k'), ('l', 'l'), ('m', 'm'), ('n', 'n'), ('o', 'o'), ('p', 'p'), ('q', 'q'), ('r', 'r'), ('s', 's'), ('t', 't'), ('u', 'u'), ('v', 'v'), ('w', 'w'), ('x', 'x'), ('y', 'y'), ('z', 'z')], max_length=1, null=True)), - ('background_color', models.CharField(default=api.models.generate_random_hex_color, max_length=7)), + ('background_color', models.CharField(default=generate_random_hex_color, max_length=7)), ('text_color', models.CharField(default='#ffffff', max_length=7)), ('created_at', models.DateTimeField(auto_now_add=True, db_index=True)), ('updated_at', models.DateTimeField(auto_now=True)), diff --git a/backend/api/migrations/0032_auto_20220127_0654.py b/backend/api/migrations/0032_auto_20220127_0654.py new file mode 100644 index 00000000..a65fc146 --- /dev/null +++ b/backend/api/migrations/0032_auto_20220127_0654.py @@ -0,0 +1,34 @@ +# Generated by Django 3.2.11 on 2022-01-27 06:54 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0031_auto_20220127_0032'), + ] + + operations = [ + migrations.SeparateDatabaseAndState( + state_operations=[ + migrations.RemoveField( + model_name='categorytype', + name='project', + ), + migrations.AlterUniqueTogether( + name='relationtypes', + unique_together=None, + ), + migrations.RemoveField( + model_name='relationtypes', + name='project', + ), + migrations.RemoveField( + model_name='spantype', + name='project', + ), + ], + database_operations=[] + ) + ] diff --git a/backend/api/migrations/0033_auto_20220127_0654.py b/backend/api/migrations/0033_auto_20220127_0654.py new file mode 100644 index 00000000..e6da429e --- /dev/null +++ b/backend/api/migrations/0033_auto_20220127_0654.py @@ -0,0 +1,41 @@ +# Generated by Django 3.2.11 on 2022-01-27 06:54 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('labels', '0003_auto_20220127_0654'), + ('api', '0032_auto_20220127_0654'), + ] + + operations = [ + migrations.SeparateDatabaseAndState( + state_operations=[ + migrations.DeleteModel( + name='CategoryType', + ), + migrations.DeleteModel( + name='RelationTypes', + ), + migrations.DeleteModel( + name='SpanType', + ), + ], + database_operations=[ + migrations.AlterModelTable( + name='CategoryType', + table='label_types_categorytype' + ), + migrations.AlterModelTable( + name='RelationTypes', + table='label_types_relationtypes' + ), + migrations.AlterModelTable( + name='SpanType', + table='label_types_spanType' + ) + ] + ) + ] diff --git a/backend/api/models.py b/backend/api/models.py index 17958267..6dc967a5 100644 --- a/backend/api/models.py +++ b/backend/api/models.py @@ -1,10 +1,7 @@ import abc -import random -import string import uuid from django.contrib.auth.models import User -from django.core.exceptions import ValidationError from django.db import models from polymorphic.models import PolymorphicModel @@ -151,87 +148,6 @@ class ImageClassificationProject(Project): return True -def generate_random_hex_color(): - return f'#{random.randint(0, 0xFFFFFF):06x}' - - -class Label(models.Model): - text = models.CharField(max_length=100, db_index=True) - prefix_key = models.CharField( - max_length=10, - blank=True, - null=True, - choices=( - ('ctrl', 'ctrl'), - ('shift', 'shift'), - ('ctrl shift', 'ctrl shift') - ) - ) - suffix_key = models.CharField( - max_length=1, - blank=True, - null=True, - choices=tuple( - (c, c) for c in string.digits + string.ascii_lowercase - ) - ) - project = models.ForeignKey( - to=Project, - on_delete=models.CASCADE, - # related_name='labels' - ) - background_color = models.CharField(max_length=7, default=generate_random_hex_color) - text_color = models.CharField(max_length=7, default='#ffffff') - created_at = models.DateTimeField(auto_now_add=True, db_index=True) - updated_at = models.DateTimeField(auto_now=True) - - def __str__(self): - return self.text - - @property - def labels(self): - raise NotImplementedError() - - def clean(self): - # Don't allow shortcut key not to have a suffix key. - if self.prefix_key and not self.suffix_key: - message = 'Shortcut key may not have a suffix key.' - raise ValidationError(message) - - # each shortcut (prefix key + suffix key) can only be assigned to one label - if self.suffix_key or self.prefix_key: - other_labels = self.labels.exclude(id=self.id) - if other_labels.filter(suffix_key=self.suffix_key, prefix_key=self.prefix_key).exists(): - message = 'A label with the shortcut already exists in the project.' - raise ValidationError(message) - - super().clean() - - class Meta: - abstract = True - constraints = [ - models.UniqueConstraint( - fields=['project', 'text'], - name='%(app_label)s_%(class)s_is_unique' - ) - ] - ordering = ['created_at'] - - -class CategoryType(Label): - - @property - def labels(self): - return CategoryType.objects.filter(project=self.project) - - -class SpanType(Label): - - @property - def labels(self): - return SpanType.objects.filter(project=self.project) - - class Example(models.Model): objects = ExampleManager() @@ -318,15 +234,3 @@ class Tag(models.Model): def __str__(self): return self.text - - -class RelationTypes(models.Model): - color = models.TextField() - name = models.TextField() - project = models.ForeignKey(Project, related_name='relation_types', on_delete=models.CASCADE) - - def __str__(self): - return self.name - - class Meta: - unique_together = ('color', 'name') diff --git a/backend/api/tests/test_models.py b/backend/api/tests/test_models.py index e9a05e17..8d1bf38f 100644 --- a/backend/api/tests/test_models.py +++ b/backend/api/tests/test_models.py @@ -1,73 +1,11 @@ -from django.core.exceptions import ValidationError -from django.db.utils import IntegrityError from django.test import TestCase from model_mommy import mommy -from api.models import (IMAGE_CLASSIFICATION, SEQUENCE_LABELING, CategoryType, - ExampleState, generate_random_hex_color) +from api.models import IMAGE_CLASSIFICATION, SEQUENCE_LABELING, ExampleState from .api.utils import prepare_project -class TestLabel(TestCase): - - def test_deny_creating_same_text(self): - label = mommy.make('CategoryType') - with self.assertRaises(IntegrityError): - mommy.make('CategoryType', project=label.project, text=label.text) - - def test_keys_uniqueness(self): - label = mommy.make('CategoryType', prefix_key='ctrl', suffix_key='a') - with self.assertRaises(ValidationError): - CategoryType(project=label.project, - text='example', - prefix_key=label.prefix_key, - suffix_key=label.suffix_key).full_clean() - - def test_suffix_key_uniqueness(self): - label = mommy.make('CategoryType', prefix_key=None, suffix_key='a') - with self.assertRaises(ValidationError): - CategoryType(project=label.project, - text='example', - prefix_key=label.prefix_key, - suffix_key=label.suffix_key).full_clean() - - def test_cannot_add_label_only_prefix_key(self): - project = mommy.make('Project') - label = CategoryType(project=project, - text='example', - prefix_key='ctrl') - with self.assertRaises(ValidationError): - label.clean() - - def test_can_add_label_only_suffix_key(self): - project = mommy.make('Project') - label = CategoryType(project=project, text='example', suffix_key='a') - try: - label.full_clean() - except ValidationError: - self.fail(msg=ValidationError) - - def test_can_add_label_suffix_key_with_prefix_key(self): - project = mommy.make('Project') - label = CategoryType(project=project, - text='example', - prefix_key='ctrl', - suffix_key='a') - try: - label.full_clean() - except ValidationError: - self.fail(msg=ValidationError) - - -class TestGeneratedColor(TestCase): - - def test_length(self): - for i in range(100): - color = generate_random_hex_color() - self.assertEqual(len(color), 7) - - class TestExampleState(TestCase): def setUp(self): diff --git a/backend/auto_labeling/pipeline/labels.py b/backend/auto_labeling/pipeline/labels.py index fabcc91c..98c19b9e 100644 --- a/backend/auto_labeling/pipeline/labels.py +++ b/backend/auto_labeling/pipeline/labels.py @@ -4,7 +4,8 @@ from typing import List from auto_labeling_pipeline.labels import Labels from django.contrib.auth.models import User -from api.models import Project, Example, CategoryType, SpanType +from api.models import Project, Example +from label_types.models import CategoryType, SpanType from labels.models import Label, Category, Span, TextLabel diff --git a/backend/data_import/pipeline/labels.py b/backend/data_import/pipeline/labels.py index 31f57f50..af5efad9 100644 --- a/backend/data_import/pipeline/labels.py +++ b/backend/data_import/pipeline/labels.py @@ -3,9 +3,8 @@ from typing import Any, Dict, Optional, Union from pydantic import BaseModel, validator -from api.models import CategoryType -from api.models import Label as LabelModel -from api.models import Project, SpanType +from api.models import Project +from label_types.models import Label as LabelModel, CategoryType, SpanType from labels.models import Category, Span, TextLabel as TL diff --git a/backend/data_import/pipeline/writers.py b/backend/data_import/pipeline/writers.py index a79bd442..e8636b79 100644 --- a/backend/data_import/pipeline/writers.py +++ b/backend/data_import/pipeline/writers.py @@ -5,7 +5,8 @@ from typing import Any, Dict, List from django.conf import settings -from api.models import CategoryType, Example, Project, SpanType +from api.models import Example, Project +from label_types.models import CategoryType, SpanType from .exceptions import FileParseException from .readers import BaseReader diff --git a/backend/data_import/tests/test_tasks.py b/backend/data_import/tests/test_tasks.py index 3f7f7a62..fed7da64 100644 --- a/backend/data_import/tests/test_tasks.py +++ b/backend/data_import/tests/test_tasks.py @@ -5,7 +5,8 @@ from django.test import TestCase from data_import.celery_tasks import import_dataset from api.models import (DOCUMENT_CLASSIFICATION, INTENT_DETECTION_AND_SLOT_FILLING, SEQ2SEQ, - SEQUENCE_LABELING, CategoryType, Example, SpanType) + SEQUENCE_LABELING, Example) +from label_types.models import CategoryType, SpanType from labels.models import Category, Span from api.tests.api.utils import prepare_project diff --git a/backend/label_types/admin.py b/backend/label_types/admin.py index 1a0979bf..048ff28b 100644 --- a/backend/label_types/admin.py +++ b/backend/label_types/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from api.models import CategoryType, SpanType +from .models import CategoryType, SpanType class LabelAdmin(admin.ModelAdmin): diff --git a/backend/label_types/migrations/0001_initial.py b/backend/label_types/migrations/0001_initial.py new file mode 100644 index 00000000..198fd680 --- /dev/null +++ b/backend/label_types/migrations/0001_initial.py @@ -0,0 +1,112 @@ +# Generated by Django 3.2.11 on 2022-01-27 06:54 + +from django.db import migrations, models +import django.db.models.deletion +import label_types.models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('api', '0032_auto_20220127_0654'), + ] + + operations = [ + migrations.SeparateDatabaseAndState( + state_operations=[ + migrations.CreateModel( + name='SpanType', + fields=[ + ('id', + models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('text', models.CharField(db_index=True, max_length=100)), + ('prefix_key', models.CharField(blank=True, choices=[('ctrl', 'ctrl'), ('shift', 'shift'), + ('ctrl shift', 'ctrl shift')], + max_length=10, null=True)), + ('suffix_key', models.CharField(blank=True, + choices=[('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), + ('4', '4'), ('5', '5'), ('6', '6'), ('7', '7'), + ('8', '8'), ('9', '9'), ('a', 'a'), ('b', 'b'), + ('c', 'c'), ('d', 'd'), ('e', 'e'), ('f', 'f'), + ('g', 'g'), ('h', 'h'), ('i', 'i'), ('j', 'j'), + ('k', 'k'), ('l', 'l'), ('m', 'm'), ('n', 'n'), + ('o', 'o'), ('p', 'p'), ('q', 'q'), ('r', 'r'), + ('s', 's'), ('t', 't'), ('u', 'u'), ('v', 'v'), + ('w', 'w'), ('x', 'x'), ('y', 'y'), ('z', 'z')], + max_length=1, null=True)), + ('background_color', + models.CharField(default=label_types.models.generate_random_hex_color, max_length=7)), + ('text_color', models.CharField(default='#ffffff', max_length=7)), + ('created_at', models.DateTimeField(auto_now_add=True, db_index=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.project')), + ], + options={ + 'ordering': ['created_at'], + 'abstract': False, + }, + ), + migrations.CreateModel( + name='RelationTypes', + fields=[ + ('id', + models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('color', models.TextField()), + ('name', models.TextField()), + ('project', + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='relation_types', + to='api.project')), + ], + ), + migrations.CreateModel( + name='CategoryType', + fields=[ + ('id', + models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('text', models.CharField(db_index=True, max_length=100)), + ('prefix_key', models.CharField(blank=True, choices=[('ctrl', 'ctrl'), ('shift', 'shift'), + ('ctrl shift', 'ctrl shift')], + max_length=10, null=True)), + ('suffix_key', models.CharField(blank=True, + choices=[('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), + ('4', '4'), ('5', '5'), ('6', '6'), ('7', '7'), + ('8', '8'), ('9', '9'), ('a', 'a'), ('b', 'b'), + ('c', 'c'), ('d', 'd'), ('e', 'e'), ('f', 'f'), + ('g', 'g'), ('h', 'h'), ('i', 'i'), ('j', 'j'), + ('k', 'k'), ('l', 'l'), ('m', 'm'), ('n', 'n'), + ('o', 'o'), ('p', 'p'), ('q', 'q'), ('r', 'r'), + ('s', 's'), ('t', 't'), ('u', 'u'), ('v', 'v'), + ('w', 'w'), ('x', 'x'), ('y', 'y'), ('z', 'z')], + max_length=1, null=True)), + ('background_color', + models.CharField(default=label_types.models.generate_random_hex_color, max_length=7)), + ('text_color', models.CharField(default='#ffffff', max_length=7)), + ('created_at', models.DateTimeField(auto_now_add=True, db_index=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.project')), + ], + options={ + 'ordering': ['created_at'], + 'abstract': False, + }, + ), + migrations.AddConstraint( + model_name='spantype', + constraint=models.UniqueConstraint(fields=('project', 'text'), + name='label_types_spantype_is_unique'), + ), + migrations.AlterUniqueTogether( + name='relationtypes', + unique_together={('color', 'name')}, + ), + migrations.AddConstraint( + model_name='categorytype', + constraint=models.UniqueConstraint(fields=('project', 'text'), + name='label_types_categorytype_is_unique'), + ), + ], + database_operations=[] + ) + ] diff --git a/backend/label_types/models.py b/backend/label_types/models.py index e69de29b..0a37ce05 100644 --- a/backend/label_types/models.py +++ b/backend/label_types/models.py @@ -0,0 +1,100 @@ +import random +import string + +from django.core.exceptions import ValidationError +from django.db import models + +from api.models import Project + + +def generate_random_hex_color(): + return f'#{random.randint(0, 0xFFFFFF):06x}' + + +class Label(models.Model): + text = models.CharField(max_length=100, db_index=True) + prefix_key = models.CharField( + max_length=10, + blank=True, + null=True, + choices=( + ('ctrl', 'ctrl'), + ('shift', 'shift'), + ('ctrl shift', 'ctrl shift') + ) + ) + suffix_key = models.CharField( + max_length=1, + blank=True, + null=True, + choices=tuple( + (c, c) for c in string.digits + string.ascii_lowercase + ) + ) + project = models.ForeignKey( + to=Project, + on_delete=models.CASCADE, + # related_name='labels' + ) + background_color = models.CharField(max_length=7, default=generate_random_hex_color) + text_color = models.CharField(max_length=7, default='#ffffff') + created_at = models.DateTimeField(auto_now_add=True, db_index=True) + updated_at = models.DateTimeField(auto_now=True) + + def __str__(self): + return self.text + + @property + def labels(self): + raise NotImplementedError() + + def clean(self): + # Don't allow shortcut key not to have a suffix key. + if self.prefix_key and not self.suffix_key: + message = 'Shortcut key may not have a suffix key.' + raise ValidationError(message) + + # each shortcut (prefix key + suffix key) can only be assigned to one label + if self.suffix_key or self.prefix_key: + other_labels = self.labels.exclude(id=self.id) + if other_labels.filter(suffix_key=self.suffix_key, prefix_key=self.prefix_key).exists(): + message = 'A label with the shortcut already exists in the project.' + raise ValidationError(message) + + super().clean() + + class Meta: + abstract = True + constraints = [ + models.UniqueConstraint( + fields=['project', 'text'], + name='%(app_label)s_%(class)s_is_unique' + ) + ] + ordering = ['created_at'] + + +class CategoryType(Label): + + @property + def labels(self): + return CategoryType.objects.filter(project=self.project) + + +class SpanType(Label): + + @property + def labels(self): + return SpanType.objects.filter(project=self.project) + + +class RelationTypes(models.Model): + color = models.TextField() + name = models.TextField() + project = models.ForeignKey(Project, related_name='relation_types', on_delete=models.CASCADE) + + def __str__(self): + return self.name + + class Meta: + unique_together = ('color', 'name') diff --git a/backend/label_types/serializers.py b/backend/label_types/serializers.py index bc06408d..07c7229a 100644 --- a/backend/label_types/serializers.py +++ b/backend/label_types/serializers.py @@ -1,7 +1,7 @@ from rest_framework import serializers from rest_framework.exceptions import ValidationError -from api.models import Label, CategoryType, SpanType, RelationTypes +from .models import Label, CategoryType, SpanType, RelationTypes class LabelSerializer(serializers.ModelSerializer): diff --git a/backend/label_types/tests/test_models.py b/backend/label_types/tests/test_models.py new file mode 100644 index 00000000..61cdded8 --- /dev/null +++ b/backend/label_types/tests/test_models.py @@ -0,0 +1,65 @@ +from django.core.exceptions import ValidationError +from django.db import IntegrityError +from django.test import TestCase +from model_mommy import mommy + +from label_types.models import CategoryType, generate_random_hex_color + + +class TestLabel(TestCase): + + def test_deny_creating_same_text(self): + label = mommy.make('CategoryType') + with self.assertRaises(IntegrityError): + mommy.make('CategoryType', project=label.project, text=label.text) + + def test_keys_uniqueness(self): + label = mommy.make('CategoryType', prefix_key='ctrl', suffix_key='a') + with self.assertRaises(ValidationError): + CategoryType(project=label.project, + text='example', + prefix_key=label.prefix_key, + suffix_key=label.suffix_key).full_clean() + + def test_suffix_key_uniqueness(self): + label = mommy.make('CategoryType', prefix_key=None, suffix_key='a') + with self.assertRaises(ValidationError): + CategoryType(project=label.project, + text='example', + prefix_key=label.prefix_key, + suffix_key=label.suffix_key).full_clean() + + def test_cannot_add_label_only_prefix_key(self): + project = mommy.make('Project') + label = CategoryType(project=project, + text='example', + prefix_key='ctrl') + with self.assertRaises(ValidationError): + label.clean() + + def test_can_add_label_only_suffix_key(self): + project = mommy.make('Project') + label = CategoryType(project=project, text='example', suffix_key='a') + try: + label.full_clean() + except ValidationError: + self.fail(msg=ValidationError) + + def test_can_add_label_suffix_key_with_prefix_key(self): + project = mommy.make('Project') + label = CategoryType(project=project, + text='example', + prefix_key='ctrl', + suffix_key='a') + try: + label.full_clean() + except ValidationError: + self.fail(msg=ValidationError) + + +class TestGeneratedColor(TestCase): + + def test_length(self): + for i in range(100): + color = generate_random_hex_color() + self.assertEqual(len(color), 7) diff --git a/backend/label_types/views.py b/backend/label_types/views.py index d53b4073..4b4b9e03 100644 --- a/backend/label_types/views.py +++ b/backend/label_types/views.py @@ -11,7 +11,7 @@ from rest_framework.response import Response from rest_framework.views import APIView from members.permissions import IsInProjectReadOnlyOrAdmin, IsProjectAdmin -from api.models import CategoryType, Label, RelationTypes, SpanType +from .models import Label, CategoryType, SpanType, RelationTypes from .exceptions import LabelValidationError from .serializers import (CategoryTypeSerializer, LabelSerializer, RelationTypesSerializer, SpanTypeSerializer) diff --git a/backend/labels/migrations/0003_auto_20220127_0654.py b/backend/labels/migrations/0003_auto_20220127_0654.py new file mode 100644 index 00000000..d759b0ea --- /dev/null +++ b/backend/labels/migrations/0003_auto_20220127_0654.py @@ -0,0 +1,35 @@ +# Generated by Django 3.2.11 on 2022-01-27 06:54 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('label_types', '0001_initial'), + ('labels', '0002_rename_annotationrelations_relation'), + ] + + operations = [ + migrations.SeparateDatabaseAndState( + state_operations=[ + migrations.AlterField( + model_name='category', + name='label', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='label_types.categorytype'), + ), + migrations.AlterField( + model_name='relation', + name='type', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, + related_name='annotation_relations', to='label_types.relationtypes'), + ), + migrations.AlterField( + model_name='span', + name='label', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='label_types.spantype'), + ), + ] + ) + ] diff --git a/backend/labels/models.py b/backend/labels/models.py index 48b40b5b..8c425db5 100644 --- a/backend/labels/models.py +++ b/backend/labels/models.py @@ -3,7 +3,8 @@ from django.core.exceptions import ValidationError from django.db import models from .managers import LabelManager, CategoryManager, SpanManager, TextLabelManager -from api.models import Example, CategoryType, SpanType, RelationTypes, Project +from api.models import Example, Project +from label_types.models import CategoryType, SpanType, RelationTypes class Label(models.Model): diff --git a/backend/labels/serializers.py b/backend/labels/serializers.py index e87c66b8..0652d267 100644 --- a/backend/labels/serializers.py +++ b/backend/labels/serializers.py @@ -1,6 +1,7 @@ from rest_framework import serializers -from api.models import CategoryType, Example, SpanType +from api.models import Example +from label_types.models import CategoryType, SpanType from .models import Category, Span, TextLabel, Relation diff --git a/backend/labels/tests/test_span.py b/backend/labels/tests/test_span.py index 79e32f20..71e25e74 100644 --- a/backend/labels/tests/test_span.py +++ b/backend/labels/tests/test_span.py @@ -5,7 +5,8 @@ from django.db import IntegrityError from django.test import TestCase from model_mommy import mommy -from api.models import SEQUENCE_LABELING, SpanType +from api.models import SEQUENCE_LABELING +from label_types.models import SpanType from labels.models import Span from api.tests.api.utils import prepare_project diff --git a/backend/metrics/views.py b/backend/metrics/views.py index 43b795fc..06137811 100644 --- a/backend/metrics/views.py +++ b/backend/metrics/views.py @@ -5,7 +5,8 @@ from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView -from api.models import Example, ExampleState, CategoryType, SpanType, Label as LabelType +from api.models import Example, ExampleState +from label_types.models import Label as LabelType, CategoryType, SpanType from labels.models import Label, Category, Span from members.models import Member from members.permissions import IsInProjectReadOnlyOrAdmin