From fa5e3f1aafb6176d53a4cb4f9f4e94690603ef54 Mon Sep 17 00:00:00 2001 From: Jason Heppler Date: Wed, 29 May 2024 15:51:59 -0500 Subject: [PATCH 1/5] refactor: Import poem data from a plain text file This commit updates the `load_stanzas.py` file to import poem data from a plain text file. It adds a new management command `handle` that takes a `--filepath` argument specifying the filepath of the plain text file to load. The content of the file is read and processed to import the stanzas into the database. This change enhances the functionality of the application by allowing the import of poem data from external sources. --- manuscript/admin.py | 1 - .../management/commands/load_stanzas.py | 63 ++++++++++++++----- 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/manuscript/admin.py b/manuscript/admin.py index 5fb1ac8..d5627f8 100644 --- a/manuscript/admin.py +++ b/manuscript/admin.py @@ -139,7 +139,6 @@ class SingleManuscriptAdmin(ImportExportModelAdmin): ) search_fields = ("siglum",) resource_class = SingleManuscriptResource - readonly_fields = ("item_id",) class FolioAdmin(admin.ModelAdmin): diff --git a/manuscript/management/commands/load_stanzas.py b/manuscript/management/commands/load_stanzas.py index 4de7177..496e9c0 100644 --- a/manuscript/management/commands/load_stanzas.py +++ b/manuscript/management/commands/load_stanzas.py @@ -1,28 +1,57 @@ +import re + from django.core.management.base import BaseCommand -from manuscript.models import Stanza +from manuscript.models import SingleManuscript, Stanza class Command(BaseCommand): - help = "Insert stanzas from a text file" + help = "Import poem data from a plain text file" def add_arguments(self, parser): parser.add_argument( - "file_path", type=str, help="The path to the file that contains the stanzas" + "--filepath", type=str, help="filepath of the plain text file to load" ) - def handle(self, *args, **kwargs): - file_path = kwargs["file_path"] + def handle(self, *args, **options): + file_path = options.get("filepath") + with open(file_path, "r", encoding="utf-8") as file: - line_counter = 0 - for line in file: - line = line.strip() - if line.startswith("[RUBRIC]") or line.isdigit(): - continue - if line != "": - line_counter += 1 - line_number = f"01.02.{line_counter:02d}" - stanza = Stanza(line=line, line_number=line_number) - stanza.save() - else: - line_counter = 0 + content = file.read() + + self.import_poem(content) + + def import_poem(self, content): + manuscript = SingleManuscript.objects.get(siglum="TEST") + book_pattern = re.compile(r"^LIBRO (\d+)$", re.MULTILINE) + stanza_pattern = re.compile(r"^(\d+)\.\s*(.*?)$", re.MULTILINE) + + book_matches = book_pattern.split(content) + for i in range(1, len(book_matches), 2): + book_number = int(book_matches[i]) + book_text = book_matches[i + 1].strip() + + stanza_splits = stanza_pattern.split(book_text) + stanza_headers = stanza_pattern.findall(book_text) + + for stanza_number, (stanza_header, stanza_text) in enumerate( + zip(stanza_headers, stanza_splits[1::3]), start=1 + ): + stanza_lines = [ + line.strip() + for line in stanza_text.strip().split("\n") + if line.strip() + ] + start_line_code = f"{book_number:02d}.{stanza_number:02d}.01" + end_line_code = ( + f"{book_number:02d}.{stanza_number:02d}.{len(stanza_lines):02d}" + ) + + Stanza.objects.create( + stanza_line_code_starts=start_line_code, + stanza_line_code_ends=end_line_code, + stanza_text="\n".join(stanza_lines), + related_manuscript=manuscript, + ) + + self.stdout.write(self.style.SUCCESS("Successfully imported the poem")) From 119b17924da2fe82a9703521c7e820ca755bfc53 Mon Sep 17 00:00:00 2001 From: Jason Heppler Date: Thu, 30 May 2024 15:29:13 -0500 Subject: [PATCH 2/5] refactor: Update StanzaAdmin to include list display and search fields This commit modifies the `StanzaAdmin` class in the `admin.py` file to include the `list_display` attribute, which displays the `stanza_line_code_starts` and `stanza_text` fields in the admin interface. It also adds the `search_fields` attribute to enable searching for stanzas based on the `stanza_text` and `stanza_line_code_starts` fields. This change improves the usability and accessibility of the admin interface for managing stanzas. --- manuscript/admin.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/manuscript/admin.py b/manuscript/admin.py index d5627f8..478b821 100644 --- a/manuscript/admin.py +++ b/manuscript/admin.py @@ -203,6 +203,14 @@ def save_related(self, request, form, formsets, change): class StanzaAdmin(admin.ModelAdmin): inlines = [StanzaVariantInline] + list_display = ( + "stanza_line_code_starts", + "stanza_text", + ) + search_fields = ( + "stanza_text", + "stanza_line_code_starts", + ) class StanzaVariantAdmin(admin.ModelAdmin): From 3239c8957f59e595ca1c48fc56a5e442f52a58c4 Mon Sep 17 00:00:00 2001 From: Jason Heppler Date: Thu, 30 May 2024 15:29:35 -0500 Subject: [PATCH 3/5] refactor: Import stanzas from plain text file This commit updates the `load_stanzas.py` file to import stanzas from a plain text file. It adds a new management command `handle` that takes a `--filepath` argument specifying the filepath of the plain text file to load. The content of the file is read and processed to import the stanzas into the database. This change enhances the functionality of the application by allowing the import of stanzas from external sources. --- .../management/commands/load_stanzas.py | 71 +++++++++++-------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/manuscript/management/commands/load_stanzas.py b/manuscript/management/commands/load_stanzas.py index 496e9c0..5cdc637 100644 --- a/manuscript/management/commands/load_stanzas.py +++ b/manuscript/management/commands/load_stanzas.py @@ -1,9 +1,12 @@ +import logging import re from django.core.management.base import BaseCommand from manuscript.models import SingleManuscript, Stanza +logger = logging.getLogger(__name__) + class Command(BaseCommand): help = "Import poem data from a plain text file" @@ -16,42 +19,48 @@ def add_arguments(self, parser): def handle(self, *args, **options): file_path = options.get("filepath") - with open(file_path, "r", encoding="utf-8") as file: + with open(file_path, "r", encoding="utf-8-sig") as file: content = file.read() self.import_poem(content) def import_poem(self, content): manuscript = SingleManuscript.objects.get(siglum="TEST") - book_pattern = re.compile(r"^LIBRO (\d+)$", re.MULTILINE) - stanza_pattern = re.compile(r"^(\d+)\.\s*(.*?)$", re.MULTILINE) + book_pattern = re.compile(r"^\s*LIBRO (\d+)", re.MULTILINE) + stanza_pattern = re.compile( + r"^(\d+)\.\s*(.*?)(?=\n\d+\.|\Z)", re.DOTALL | re.MULTILINE + ) book_matches = book_pattern.split(content) - for i in range(1, len(book_matches), 2): - book_number = int(book_matches[i]) - book_text = book_matches[i + 1].strip() - - stanza_splits = stanza_pattern.split(book_text) - stanza_headers = stanza_pattern.findall(book_text) - - for stanza_number, (stanza_header, stanza_text) in enumerate( - zip(stanza_headers, stanza_splits[1::3]), start=1 - ): - stanza_lines = [ - line.strip() - for line in stanza_text.strip().split("\n") - if line.strip() - ] - start_line_code = f"{book_number:02d}.{stanza_number:02d}.01" - end_line_code = ( - f"{book_number:02d}.{stanza_number:02d}.{len(stanza_lines):02d}" - ) - - Stanza.objects.create( - stanza_line_code_starts=start_line_code, - stanza_line_code_ends=end_line_code, - stanza_text="\n".join(stanza_lines), - related_manuscript=manuscript, - ) - - self.stdout.write(self.style.SUCCESS("Successfully imported the poem")) + if book_matches[0] == "": + book_matches = book_matches[1:] + + for i in range(0, len(book_matches), 2): + book_number = int( + book_matches[i] + ) # Extract book number from "LIBRO X" string + book_text = book_matches[ + i + 1 + ].strip() # Get the corresponding book content + + stanza_matches = stanza_pattern.findall(book_text) + + for stanza_number, stanza_text in stanza_matches: + stanza_number = int(stanza_number) + stanza_text = stanza_text.strip() + + stanza_lines = stanza_text.split("\n") + + for line_number, line_text in enumerate(stanza_lines, start=1): + line_code = ( + f"{book_number:02d}.{stanza_number:02d}.{line_number:02d}" + ) + # print(f"Line code: {line_code}, Line text: {line_text}") + + Stanza.objects.create( + stanza_line_code_starts=line_code, + stanza_text=line_text, + related_manuscript=manuscript, + ) + + self.stdout.write(self.style.SUCCESS("Successfully imported the stanzas")) From 0b9c020d8df773a9b637fba12e427e05164d2796 Mon Sep 17 00:00:00 2001 From: Jason Heppler Date: Thu, 30 May 2024 15:30:00 -0500 Subject: [PATCH 4/5] refactor: Add ordering to Stanza model This commit adds the `ordering` attribute to the `Stanza` model in the `models.py` file. The `ordering` attribute specifies the default ordering of stanzas based on their `id` field. This change ensures that stanzas are consistently ordered when retrieved from the database. This improvement enhances the predictability and consistency of stanza ordering in the application. --- manuscript/models.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/manuscript/models.py b/manuscript/models.py index 6c14921..717f08a 100644 --- a/manuscript/models.py +++ b/manuscript/models.py @@ -5,6 +5,8 @@ from django.conf import settings from django.core.exceptions import ValidationError from django.db import models +from django.db.models import IntegerField +from django.db.models.functions import Cast from django_prose_editor.fields import ProseEditorField from prose.fields import RichTextField @@ -347,6 +349,9 @@ def derive_folio_location(self): manuscript=self.related_folio.manuscript, folio_number=book ).first() + class Meta: + ordering = ["id"] + class Folio(models.Model): """This provides a way to collect several stanzas onto a single page, and associate them with a single manuscript.""" From 636526bfc2274f3027f4f11309fabdff4490da1e Mon Sep 17 00:00:00 2001 From: Jason Heppler Date: Thu, 30 May 2024 15:30:51 -0500 Subject: [PATCH 5/5] feat: Add display of the manuscript text --- ...lter_folio_options_alter_stanza_options.py | 20 +++++++++++++++++++ manuscript/views.py | 5 ++++- templates/index.html | 5 +++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 manuscript/migrations/0071_alter_folio_options_alter_stanza_options.py diff --git a/manuscript/migrations/0071_alter_folio_options_alter_stanza_options.py b/manuscript/migrations/0071_alter_folio_options_alter_stanza_options.py new file mode 100644 index 0000000..c07d899 --- /dev/null +++ b/manuscript/migrations/0071_alter_folio_options_alter_stanza_options.py @@ -0,0 +1,20 @@ +# Generated by Django 5.0.2 on 2024-05-30 16:43 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("manuscript", "0070_alter_location_line_code_alter_location_placename_id"), + ] + + operations = [ + migrations.AlterModelOptions( + name="folio", + options={"ordering": ["folio_number"]}, + ), + migrations.AlterModelOptions( + name="stanza", + options={"ordering": ["id"]}, + ), + ] diff --git a/manuscript/views.py b/manuscript/views.py index d43199d..27516a9 100644 --- a/manuscript/views.py +++ b/manuscript/views.py @@ -3,6 +3,9 @@ from django.urls import reverse from django.views import generic +from manuscript.models import Stanza + def index(request: HttpRequest): - return render(request, "index.html", {}) + stanzas = Stanza.objects.all().order_by("stanza_line_code_starts") + return render(request, "index.html", {"stanzas": stanzas}) diff --git a/templates/index.html b/templates/index.html index 65d47a9..634fd25 100644 --- a/templates/index.html +++ b/templates/index.html @@ -4,4 +4,9 @@

Homepage

{% block content %} +

Text of the manuscript

+ {% for stanza in stanzas %} +

{{ stanza.stanza_text }}

+ {% endfor %} + {% endblock content %} \ No newline at end of file