mirror of https://github.com/doccano/doccano.git
Browse Source
Merge pull request #1655 from doccano/enhancement/separateLabelType
Merge pull request #1655 from doccano/enhancement/separateLabelType
[Enhancement] Separate label type apppull/1656/head
Hiroki Nakayama
2 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 623 additions and 355 deletions
Unified View
Diff Options
-
21backend/api/admin.py
-
5backend/api/migrations/0018_alter_label_background_color.py
-
7backend/api/migrations/0020_auto_20211221_1415.py
-
34backend/api/migrations/0032_auto_20220127_0654.py
-
41backend/api/migrations/0033_auto_20220127_0654.py
-
96backend/api/models.py
-
101backend/api/serializers.py
-
64backend/api/tests/test_models.py
-
48backend/api/urls.py
-
1backend/app/settings.py
-
1backend/app/urls.py
-
3backend/auto_labeling/pipeline/labels.py
-
17backend/data_import/pipeline/labels.py
-
3backend/data_import/pipeline/writers.py
-
3backend/data_import/tests/test_tasks.py
-
0backend/label_types/__init__.py
-
21backend/label_types/admin.py
-
6backend/label_types/apps.py
-
0backend/label_types/exceptions.py
-
112backend/label_types/migrations/0001_initial.py
-
19backend/label_types/migrations/0002_rename_relationtypes_relationtype.py
-
0backend/label_types/migrations/__init__.py
-
100backend/label_types/models.py
-
88backend/label_types/serializers.py
-
0backend/label_types/tests/__init__.py
-
65backend/label_types/tests/test_models.py
-
4backend/label_types/tests/test_views.py
-
54backend/label_types/urls.py
-
15backend/label_types/views.py
-
35backend/labels/migrations/0003_auto_20220127_0654.py
-
5backend/labels/models.py
-
3backend/labels/serializers.py
-
3backend/labels/tests/test_span.py
-
3backend/metrics/views.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=[] |
||||
|
) |
||||
|
] |
@ -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' |
||||
|
) |
||||
|
] |
||||
|
) |
||||
|
] |
@ -0,0 +1,21 @@ |
|||||
|
from django.contrib import admin |
||||
|
|
||||
|
from .models import CategoryType, SpanType |
||||
|
|
||||
|
|
||||
|
class LabelAdmin(admin.ModelAdmin): |
||||
|
list_display = ('text', 'project', 'text_color', 'background_color') |
||||
|
ordering = ('project',) |
||||
|
search_fields = ('text',) |
||||
|
|
||||
|
|
||||
|
class CategoryTypeAdmin(LabelAdmin): |
||||
|
pass |
||||
|
|
||||
|
|
||||
|
class SpanTypeAdmin(LabelAdmin): |
||||
|
pass |
||||
|
|
||||
|
|
||||
|
admin.site.register(CategoryType, CategoryTypeAdmin) |
||||
|
admin.site.register(SpanType, SpanTypeAdmin) |
@ -0,0 +1,6 @@ |
|||||
|
from django.apps import AppConfig |
||||
|
|
||||
|
|
||||
|
class LabelTypesConfig(AppConfig): |
||||
|
default_auto_field = 'django.db.models.BigAutoField' |
||||
|
name = 'label_types' |
@ -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=[] |
||||
|
) |
||||
|
] |
@ -0,0 +1,19 @@ |
|||||
|
# Generated by Django 3.2.11 on 2022-01-27 07:27 |
||||
|
|
||||
|
from django.db import migrations |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('labels', '0003_auto_20220127_0654'), |
||||
|
('api', '0033_auto_20220127_0654'), |
||||
|
('label_types', '0001_initial'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.RenameModel( |
||||
|
old_name='RelationTypes', |
||||
|
new_name='RelationType', |
||||
|
), |
||||
|
] |
@ -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 LabelType(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(LabelType): |
||||
|
|
||||
|
@property |
||||
|
def labels(self): |
||||
|
return CategoryType.objects.filter(project=self.project) |
||||
|
|
||||
|
|
||||
|
class SpanType(LabelType): |
||||
|
|
||||
|
@property |
||||
|
def labels(self): |
||||
|
return SpanType.objects.filter(project=self.project) |
||||
|
|
||||
|
|
||||
|
class RelationType(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') |
@ -0,0 +1,88 @@ |
|||||
|
from rest_framework import serializers |
||||
|
from rest_framework.exceptions import ValidationError |
||||
|
|
||||
|
from .models import LabelType, CategoryType, SpanType, RelationType |
||||
|
|
||||
|
|
||||
|
class LabelSerializer(serializers.ModelSerializer): |
||||
|
|
||||
|
def validate(self, attrs): |
||||
|
prefix_key = attrs.get('prefix_key') |
||||
|
suffix_key = attrs.get('suffix_key') |
||||
|
|
||||
|
# In the case of user don't set any shortcut key. |
||||
|
if prefix_key is None and suffix_key is None: |
||||
|
return super().validate(attrs) |
||||
|
|
||||
|
# Don't allow shortcut key not to have a suffix key. |
||||
|
if prefix_key and not suffix_key: |
||||
|
raise ValidationError('Shortcut key may not have a suffix key.') |
||||
|
|
||||
|
# Don't allow to save same shortcut key when prefix_key is null. |
||||
|
try: |
||||
|
context = self.context['request'].parser_context |
||||
|
project_id = context['kwargs']['project_id'] |
||||
|
label_id = context['kwargs'].get('label_id') |
||||
|
except (AttributeError, KeyError): |
||||
|
pass # unit tests don't always have the correct context set up |
||||
|
else: |
||||
|
conflicting_labels = self.Meta.model.objects.filter( |
||||
|
suffix_key=suffix_key, |
||||
|
prefix_key=prefix_key, |
||||
|
project=project_id, |
||||
|
) |
||||
|
|
||||
|
if label_id is not None: |
||||
|
conflicting_labels = conflicting_labels.exclude(id=label_id) |
||||
|
|
||||
|
if conflicting_labels.exists(): |
||||
|
raise ValidationError('Duplicate shortcut key.') |
||||
|
|
||||
|
return super().validate(attrs) |
||||
|
|
||||
|
class Meta: |
||||
|
model = LabelType |
||||
|
fields = ( |
||||
|
'id', |
||||
|
'text', |
||||
|
'prefix_key', |
||||
|
'suffix_key', |
||||
|
'background_color', |
||||
|
'text_color', |
||||
|
) |
||||
|
|
||||
|
|
||||
|
class CategoryTypeSerializer(LabelSerializer): |
||||
|
class Meta: |
||||
|
model = CategoryType |
||||
|
fields = ( |
||||
|
'id', |
||||
|
'text', |
||||
|
'prefix_key', |
||||
|
'suffix_key', |
||||
|
'background_color', |
||||
|
'text_color', |
||||
|
) |
||||
|
|
||||
|
|
||||
|
class SpanTypeSerializer(LabelSerializer): |
||||
|
class Meta: |
||||
|
model = SpanType |
||||
|
fields = ( |
||||
|
'id', |
||||
|
'text', |
||||
|
'prefix_key', |
||||
|
'suffix_key', |
||||
|
'background_color', |
||||
|
'text_color', |
||||
|
) |
||||
|
|
||||
|
|
||||
|
class RelationTypesSerializer(serializers.ModelSerializer): |
||||
|
|
||||
|
def validate(self, attrs): |
||||
|
return super().validate(attrs) |
||||
|
|
||||
|
class Meta: |
||||
|
model = RelationType |
||||
|
fields = ('id', 'color', 'name') |
@ -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) |
@ -0,0 +1,54 @@ |
|||||
|
from django.urls import path |
||||
|
|
||||
|
from .views import CategoryTypeList, CategoryTypeDetail, CategoryTypeUploadAPI |
||||
|
from .views import SpanTypeList, SpanTypeDetail, SpanTypeUploadAPI |
||||
|
from .views import RelationTypeList, RelationTypeDetail, RelationTypeUploadAPI |
||||
|
|
||||
|
|
||||
|
urlpatterns = [ |
||||
|
path( |
||||
|
route='category-types', |
||||
|
view=CategoryTypeList.as_view(), |
||||
|
name='category_types' |
||||
|
), |
||||
|
path( |
||||
|
route='category-types/<int:label_id>', |
||||
|
view=CategoryTypeDetail.as_view(), |
||||
|
name='category_type' |
||||
|
), |
||||
|
path( |
||||
|
route='span-types', |
||||
|
view=SpanTypeList.as_view(), |
||||
|
name='span_types' |
||||
|
), |
||||
|
path( |
||||
|
route='span-types/<int:label_id>', |
||||
|
view=SpanTypeDetail.as_view(), |
||||
|
name='span_type' |
||||
|
), |
||||
|
path( |
||||
|
route='category-type-upload', |
||||
|
view=CategoryTypeUploadAPI.as_view(), |
||||
|
name='category_type_upload' |
||||
|
), |
||||
|
path( |
||||
|
route='span-type-upload', |
||||
|
view=SpanTypeUploadAPI.as_view(), |
||||
|
name='span_type_upload' |
||||
|
), |
||||
|
path( |
||||
|
route='relation_types', |
||||
|
view=RelationTypeList.as_view(), |
||||
|
name='relation_types_list' |
||||
|
), |
||||
|
path( |
||||
|
route='relation_type-upload', |
||||
|
view=RelationTypeUploadAPI.as_view(), |
||||
|
name='relation_type-upload' |
||||
|
), |
||||
|
path( |
||||
|
route='relation_types/<int:relation_type_id>', |
||||
|
view=RelationTypeDetail.as_view(), |
||||
|
name='relation_type_detail' |
||||
|
), |
||||
|
] |
@ -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'), |
||||
|
), |
||||
|
] |
||||
|
) |
||||
|
] |
Write
Preview
Loading…
Cancel
Save