From 60f3862c7095e9bfc371aac2b9aab886e594ef36 Mon Sep 17 00:00:00 2001 From: Ben Silverman Date: Tue, 5 Dec 2023 15:06:52 -0500 Subject: [PATCH] Use boolean is_structured_data, not data_type for seeAlso (#958) --- apps/iiif/manifests/admin.py | 2 +- .../0060_relatedlink_is_structured_data.py | 38 +++++++++++++++++++ apps/iiif/manifests/models.py | 34 ++++++++--------- apps/iiif/manifests/tests/tests.py | 2 +- apps/ingest/services.py | 5 ++- 5 files changed, 60 insertions(+), 21 deletions(-) create mode 100644 apps/iiif/manifests/migrations/0060_relatedlink_is_structured_data.py diff --git a/apps/iiif/manifests/admin.py b/apps/iiif/manifests/admin.py index 6a39b171..50288374 100644 --- a/apps/iiif/manifests/admin.py +++ b/apps/iiif/manifests/admin.py @@ -39,7 +39,7 @@ class RelatedLinksInline(admin.TabularInline): exclude = ("id",) fields = ( "link", - "data_type", + "is_structured_data", "format", ) extra = 1 diff --git a/apps/iiif/manifests/migrations/0060_relatedlink_is_structured_data.py b/apps/iiif/manifests/migrations/0060_relatedlink_is_structured_data.py new file mode 100644 index 00000000..dfaea844 --- /dev/null +++ b/apps/iiif/manifests/migrations/0060_relatedlink_is_structured_data.py @@ -0,0 +1,38 @@ +# Generated by Django 3.2.12 on 2023-12-05 19:59 + +from django.db import migrations, models + + +def populate_is_structured_data(apps, schema_editor): + # Data migration to populate RelatedLink.is_structured_data for existing data + RelatedLink = apps.get_model("manifests", "RelatedLink") + rl_set = RelatedLink.objects.all() + for rl in rl_set: + # Assume all existing RelatedLinks are structured data, since they were previously only + # being added in Remote ingests when there was an existing manifest (which is structured + # data) + rl.is_structured_data = True + RelatedLink.objects.bulk_update(rl_set, ["is_structured_data"], batch_size=1000) + + +class Migration(migrations.Migration): + dependencies = [ + ("manifests", "0059_alter_relatedlink_id"), + ] + + operations = [ + migrations.AddField( + model_name="relatedlink", + name="is_structured_data", + field=models.BooleanField( + default=False, + help_text="True if this link is structured data that should appear in the manifest's 'seeAlso' field; if false, the link will appear in the 'related' field instead. Leave unchecked if unsure.", + ), + ), + migrations.AlterField( + model_name="relatedlink", + name="data_type", + field=models.CharField(default="Dataset", max_length=255), + ), + migrations.RunPython(populate_is_structured_data, migrations.RunPython.noop), + ] diff --git a/apps/iiif/manifests/models.py b/apps/iiif/manifests/models.py index f5d5cc85..f5471103 100644 --- a/apps/iiif/manifests/models.py +++ b/apps/iiif/manifests/models.py @@ -288,12 +288,12 @@ def external_links(self): "see_also": [ link.link for link in related_links - if link.data_type.lower() == "dataset" + if link.is_structured_data ], "related": [ link.link for link in related_links - if link.data_type.lower() != "dataset" + if not link.is_structured_data ], } @@ -304,18 +304,15 @@ def see_also_links(self): :return: List of links to structured data describing Manifest :rtype: list """ - links = [] - for link in self.relatedlink_set.all(): - if link.data_type.lower() == "dataset": - links.append( - { - "@id": link.link, - "format": link.format, - } - if link.format - else link.link - ) - return links + return [ + { + "@id": link.link, + "format": link.format, + } + if link.format + else link.link + for link in self.relatedlink_set.filter(is_structured_data=True) + ] # TODO: Is this needed? It doesn't seem to be called anywhere. # Could we just use the label as is? @@ -398,9 +395,12 @@ class RelatedLink(models.Model): data_type = models.CharField( max_length=255, default='Dataset', - help_text="Leave as 'Dataset' for structured data describing this document (e.g. a " + - "remote manifest) and this link will appear in 'seeAlso'; change to any other value and " + - "it will only appear in the 'related' property of the manifest.", + ) + is_structured_data = models.BooleanField( + default=False, + help_text="True if this link is structured data that should appear in the manifest's " + + "'seeAlso' field; if false, the link will appear in the 'related' field instead. Leave " + + "unchecked if unsure.", ) label = GenericRelation(ValueByLanguage) format = models.CharField(max_length=255, choices=Choices.MIMETYPES, blank=True, null=True) diff --git a/apps/iiif/manifests/tests/tests.py b/apps/iiif/manifests/tests/tests.py index 16be42f3..42ffed92 100644 --- a/apps/iiif/manifests/tests/tests.py +++ b/apps/iiif/manifests/tests/tests.py @@ -177,7 +177,7 @@ def test_serialized_related_links(self): ) assert not no_links['seeAlso'] - link = RelatedLink(link='images.org', manifest=manifest) + link = RelatedLink(link='images.org', manifest=manifest, is_structured_data=True) link.save() manifest.refresh_from_db() diff --git a/apps/ingest/services.py b/apps/ingest/services.py index 365283df..47f829d3 100644 --- a/apps/ingest/services.py +++ b/apps/ingest/services.py @@ -58,7 +58,7 @@ def create_related_links(manifest, related_str): manifest=manifest, link=link, format=format or "text/html", # assume web page if MIME type cannot be determined - data_type="Document", # assume this is not meant for seeAlso + is_structured_data=False, # assume this is not meant for seeAlso ) def create_manifest(ingest): @@ -108,7 +108,8 @@ def create_manifest(ingest): RelatedLink( manifest=manifest, link=ingest.remote_url, - format='application/ld+json' + format='application/ld+json', + is_structured_data=True, ).save() return manifest