Commit 816b5bed1645ea179a72a901bb7a8cff195ece72
1 parent
f38c6209
Change "name" field constraint, add moving sudocuments and fix bug when splittin…
…g document after deleting one with smaller sequence
Showing
5 changed files
with
55 additions
and
8 deletions
collector/storage/models.py
... | ... | @@ -3,6 +3,7 @@ import os |
3 | 3 | from django.contrib.postgres.fields import ArrayField, JSONField |
4 | 4 | from django.contrib.auth import get_user_model |
5 | 5 | from django.db import models |
6 | +from django.db.models import UniqueConstraint | |
6 | 7 | from partial_date import PartialDateField |
7 | 8 | from languages.fields import LanguageField |
8 | 9 | |
... | ... | @@ -12,7 +13,7 @@ User = get_user_model() |
12 | 13 | |
13 | 14 | |
14 | 15 | class Document(models.Model): |
15 | - name = models.TextField(unique=True) | |
16 | + name = models.TextField() | |
16 | 17 | source_id = models.CharField(max_length=32) |
17 | 18 | lang = models.CharField(max_length=5) |
18 | 19 | original_lang = LanguageField() |
... | ... | @@ -144,6 +145,9 @@ class Document(models.Model): |
144 | 145 | class Meta: |
145 | 146 | db_table = 'document' |
146 | 147 | ordering = ['id'] |
148 | + constraints = [ | |
149 | + models.UniqueConstraint(fields=['name', 'sequence'], name='unique subdocument sequence') | |
150 | + ] | |
147 | 151 | |
148 | 152 | def __str__(self): |
149 | 153 | return str(self.id) + '-' + self.name |
... | ... |
collector/storage/static/storage/css/document.css
collector/storage/templates/storage/annotation.html
... | ... | @@ -108,12 +108,18 @@ |
108 | 108 | <tbody> |
109 | 109 | {% for subdocument in subdocuments %} |
110 | 110 | <tr> |
111 | - <td><a href="{% url 'annotation' subdocument.id %}">{{ subdocument.name }}</a></td> | |
111 | + <td><a href="{% url 'annotation' subdocument.id %}">{{ subdocument.name }}-{{ subdocument.id }}</a></td> | |
112 | 112 | <td>{{ subdocument.sequence }}</td> |
113 | 113 | <td class="actions"> |
114 | 114 | {% if user.is_authenticated %} |
115 | - <i class="material-icons button" title="Edytuj">edit</i> | |
116 | - <i class="material-icons button" title="Usuń">delete</i> | |
115 | + <a class="button" | |
116 | + href="{% url 'move_subdoc' subdocument.id 'up' %}"> | |
117 | + <i class="material-icons button arrow" title="Przesuń w górę">arrow_drop_up</i> | |
118 | + </a> | |
119 | + <a class="button" | |
120 | + href="{% url 'move_subdoc' subdocument.id 'down' %}"> | |
121 | + <i class="material-icons button arrow" title="Przesuń w dół">arrow_drop_down</i> | |
122 | + </a> | |
117 | 123 | {% endif %} |
118 | 124 | </td> |
119 | 125 | </tr> |
... | ... |
collector/storage/urls.py
... | ... | @@ -40,7 +40,8 @@ urlpatterns = [ |
40 | 40 | path('keyword/add/<str:doc_id>', login_required(views.add_keyword), name='add_keyword'), |
41 | 41 | path('keyword/edit/<str:doc_id>/<int:pk>', login_required(views.edit_keyword), name='edit_keyword'), |
42 | 42 | path('keyword/delete/<str:doc_id>/<int:pk>', login_required(views.delete_keyword), name='delete_keyword'), |
43 | - path('split-doc/<str:doc_id>/', login_required(views.split_doc), name='split_doc'), | |
43 | + path('split-doc/<str:doc_id>', login_required(views.split_doc), name='split_doc'), | |
44 | + path('move-subdoc/<str:subdoc_id>/<str:direction>', login_required(views.move_subdoc), name='move_subdoc'), | |
44 | 45 | path('revert-subdoc-division/<int:pk>/', login_required(views.RevertSubdocDivisionView.as_view()), |
45 | 46 | name='revert_subdoc_division'), |
46 | 47 | path('md-name-autocomplete/', views.md_name_autocomplete, name='md_name_autocomplete'), |
... | ... |
collector/storage/views.py
... | ... | @@ -16,6 +16,7 @@ from django.db.models import Q |
16 | 16 | from django.template.loader import render_to_string |
17 | 17 | |
18 | 18 | from keras import backend |
19 | +from sys import maxsize | |
19 | 20 | |
20 | 21 | from .forms import ChunkForm, ParticipantForm, SubchunkForm, MetadataForm, DocDetailsForm, KeywordForm, DocSplitForm, \ |
21 | 22 | MoveChunkForm, SubDocDetailsForm, AuthorForm |
... | ... | @@ -526,7 +527,7 @@ class AnnotationView(View): |
526 | 527 | context = {'document': None} |
527 | 528 | try: |
528 | 529 | doc = Document.objects.get(id=doc_id) |
529 | - subdocuments = Document.objects.filter(parent=doc) | |
530 | + subdocuments = Document.objects.filter(parent=doc).order_by('sequence') | |
530 | 531 | metadata = doc.metadata.order_by('sequence') |
531 | 532 | chunks = doc.chunks.order_by('sequence') |
532 | 533 | keywords = doc.keywords.all() |
... | ... | @@ -830,7 +831,7 @@ def split_doc(request, doc_id): |
830 | 831 | parent = document |
831 | 832 | else: |
832 | 833 | parent = document.parent |
833 | - new_document = Document.objects.create(name=parent.name + f'_text-{sequence + 1}', | |
834 | + new_document = Document.objects.create(name=parent.name, | |
834 | 835 | lang=parent.lang, |
835 | 836 | original_lang=parent.original_lang, |
836 | 837 | pipeline=parent.pipeline, |
... | ... | @@ -841,7 +842,7 @@ def split_doc(request, doc_id): |
841 | 842 | status=parent.status, |
842 | 843 | parent=parent, |
843 | 844 | processing_status=parent.processing_status, |
844 | - sequence=sequence+1) | |
845 | + sequence=sequence + 1) | |
845 | 846 | new_document.chunks.set(chunks.filter(sequence__range=(chunk_beg, chunk_end))) |
846 | 847 | new_document.save() |
847 | 848 | document.chunks.set(chunks.filter(sequence__lt=chunk_beg) | chunks.filter(sequence__gt=chunk_end)) |
... | ... | @@ -855,6 +856,37 @@ def split_doc(request, doc_id): |
855 | 856 | 'submit_btn_text': 'Podziel'}) |
856 | 857 | |
857 | 858 | |
859 | +def swap_subdocs(direction, subdoc, subdoc_seq, temp_seq, max_seq): | |
860 | + sign = None | |
861 | + if direction == 'up' and subdoc_seq > 1: | |
862 | + sign = '-' | |
863 | + elif direction == 'down' and subdoc_seq < max_seq: | |
864 | + sign = '+' | |
865 | + if sign is not None: | |
866 | + neighbour = Document.objects.get(sequence=eval(f'{str(subdoc_seq)} {sign} 1')) | |
867 | + neighbour.sequence = temp_seq | |
868 | + neighbour.save() | |
869 | + subdoc.sequence = eval(f'{str(subdoc_seq)} {sign} 1') | |
870 | + subdoc.save() | |
871 | + neighbour.sequence = subdoc_seq | |
872 | + neighbour.save() | |
873 | + | |
874 | + | |
875 | +def move_subdoc(request, subdoc_id, direction): | |
876 | + subdoc = Document.objects.get(id=subdoc_id) | |
877 | + subdoc_seq = subdoc.sequence | |
878 | + parent_doc = Document.objects.get(id=subdoc_id).parent | |
879 | + max_seq_doc = Document.objects.filter(parent=parent_doc).order_by('-sequence').first() | |
880 | + if max_seq_doc is not None: | |
881 | + max_seq = max_seq_doc.sequence | |
882 | + temp_seq = max_seq + 10 | |
883 | + else: | |
884 | + max_seq = 0 | |
885 | + temp_seq = 10 | |
886 | + swap_subdocs(direction, subdoc, subdoc_seq, temp_seq, max_seq) | |
887 | + return HttpResponseRedirect(reverse('annotation', kwargs={'doc_id': parent_doc.id})) | |
888 | + | |
889 | + | |
858 | 890 | class RevertSubdocDivisionView(DeleteView): |
859 | 891 | model = Document |
860 | 892 | template_name = 'storage/delete.html' |
... | ... |