Skip to content

Commit

Permalink
Merge pull request #1733 from Princeton-CDH/feature/1687-people-dates
Browse files Browse the repository at this point in the history
Separate person document-based dates active and dates mentioned as deceased (#1687)
  • Loading branch information
blms authored Jan 29, 2025
2 parents f3f3fe7 + 904bb88 commit 4609eb4
Show file tree
Hide file tree
Showing 11 changed files with 733 additions and 380 deletions.
15 changes: 10 additions & 5 deletions geniza/entities/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,11 +282,12 @@ class PersonAdmin(TabbedTranslationAdmin, SortableAdminBase, admin.ModelAdmin):
"role",
"has_page",
"date",
"automatic_date",
"active_dates",
"deceased_mention_dates",
"description",
"tags",
)
readonly_fields = ("automatic_date",)
readonly_fields = ("active_dates", "deceased_mention_dates")
inlines = (
NameInline,
FootnoteInline,
Expand Down Expand Up @@ -406,9 +407,13 @@ def get_urls(self):
]
return urls + super().get_urls()

def automatic_date(self, obj):
"""Display automatically generated date/date range for an event as a formatted string"""
return standard_date_display(obj.documents_date_range)
def active_dates(self, obj):
"""Display automatically generated active date/date range for a person as a formatted string"""
return standard_date_display(obj.active_date_range)

def deceased_mention_dates(self, obj):
"""Display automatically generated deceased date/date range for a person as a formatted string"""
return standard_date_display(obj.deceased_date_range)

actions = (export_to_csv, merge_people)

Expand Down
3 changes: 2 additions & 1 deletion geniza/entities/metadata_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ def get_export_data_dict(self, person):
),
"gender": person.get_gender_display(),
"social_role": str(person.role),
"auto_date_range": standard_date_display(person.documents_date_range),
"active_date_range": standard_date_display(person.active_date_range),
"deceased_date_range": standard_date_display(person.deceased_date_range),
"manual_date_range": person.date,
"description": person.description,
"related_people_count": person.related_people_count,
Expand Down
43 changes: 36 additions & 7 deletions geniza/entities/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,13 @@ class DocumentDatableMixin:

@property
def documents_date_range(self):
"""Standardized range of dates across associated documents"""
"""Compute the total range of dates across all associated documents"""
return self.get_date_range(self.documents.all())

def get_date_range(self, doc_set):
"""Standardized range of dates across a set of documents"""
full_range = [None, None]
for doc in self.documents.all():
for doc in doc_set:
# get each doc's full range, including inferred and on-document
doc_range = doc.dating_range()
# if doc has a range, and the range is not [None, None], compare
Expand All @@ -121,7 +125,6 @@ def documents_date_range(self):
full_range = PartialDate.get_date_range(
old_range=full_range, new_range=[start, end]
)

# prune Nones and use isoformat for standardized representation
full_range = [d.isoformat() for d in full_range if d]
if len(full_range) == 2 and full_range[0] == full_range[1]:
Expand Down Expand Up @@ -414,22 +417,27 @@ def __str__(self):

@property
def date_str(self):
"""Return a formatted string for the person's date range, for use in public site.
"""Return a formatted string for the person's active date range, for use in public site.
CE date override takes highest precedence, then fallback to computed date range from
associated documents if override is unset.
"""
return (
standard_date_display(self.date)
or standard_date_display(self.documents_date_range)
or standard_date_display(self.active_date_range)
or ""
)

@property
def deceased_date_str(self):
"""Return a formatted string for the person's mentioned as deceased date range."""
return standard_date_display(self.deceased_date_range) or ""

def solr_date_range(self):
"""Return the person's date range as a Solr date range."""
if self.date:
solr_dating_range = self.date.split("/")
else:
solr_dating_range = self.documents_date_range.split("/")
solr_dating_range = self.active_date_range.split("/")
if solr_dating_range:
# if a single date instead of a range, just return that date
if (
Expand Down Expand Up @@ -647,6 +655,27 @@ def related_people(self):

return relation_list

@property
def active_date_range(self):
"""Standardized range of dates across documents where a person is (presumed) alive"""
relations = self.persondocumentrelation_set.exclude(
type__name__icontains="deceased"
)
doc_ids = relations.values_list("document__pk", flat=True)
docs = Document.objects.filter(pk__in=doc_ids)
return self.get_date_range(docs)

@property
def deceased_date_range(self):
"""Standardized range of dates across associated documents where the relationship is
'Mentioned (deceased)'"""
relations = self.persondocumentrelation_set.filter(
type__name__icontains="deceased"
)
doc_ids = relations.values_list("document__pk", flat=True)
docs = Document.objects.filter(pk__in=doc_ids)
return self.get_date_range(docs)

def merge_with(self, merge_people, user=None):
"""Merge the specified people into this one. Combines all metadata
into this person and creates a log entry documenting the merge.
Expand Down Expand Up @@ -903,7 +932,7 @@ def index_data(self):
for date in (
self.date.split("/")
if self.date
else self.documents_date_range.split("/")
else self.active_date_range.split("/")
)
]
index_data.update(
Expand Down
21 changes: 17 additions & 4 deletions geniza/entities/templates/entities/person_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,23 @@ <h2 class="sr-only">
{# Translators: label for a person's gender #}
<dt>{% translate 'Gender' %}</dt>
<dd>{{ person.get_gender_display }}</dd>
{% if person.date_str %}
{# Translators: label for a person's active dates in the PGP #}
<dt>{% translate 'Active dates' %}</dt>
<dd>{{ person.date_str }}</dd>
{% if person.date_str or person.deceased_date_str %}
{# Translators: label for the dates of a person's appearances in PGP documents #}
<dt>{% translate 'Dates' %}</dt>
<dd>
<dl class="person-dates">
{% if person.date_str %}
{# Translators: label for a person's active dates in the PGP #}
<dt>{% translate 'Active dates' %}</dt>
<dd>{{ person.date_str }}</dd>
{% endif %}
{% if person.deceased_date_str %}
{# Translators: label for a person's date range when mentioned after death in PGP documents #}
<dt>{% translate 'Posthumous mentions' %}</dt>
<dd>{{ person.deceased_date_str }}</dd>
{% endif %}
</dl>
</dd>
{% endif %}
{% if person.role %}
<dt>
Expand Down
25 changes: 25 additions & 0 deletions geniza/entities/tests/test_entities_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from django.urls import reverse
from pytest_django.asserts import assertContains, assertNotContains

from geniza.corpus.dates import standard_date_display
from geniza.corpus.models import Dating, Document, LanguageScript
from geniza.entities.admin import (
NameInlineFormSet,
Expand Down Expand Up @@ -230,6 +231,30 @@ def test_export_relations_to_csv(self, person, person_multiname):
assert str(person_multiname) in content
assert "Partner" in content

def test_date_ranges(self, person, document, join):
document.doc_date_standard = "1200/1300"
document.save()
(pdrtype, _) = PersonDocumentRelationType.objects.get_or_create(name="test")
PersonDocumentRelation.objects.create(
person=person, document=document, type=pdrtype
)
(deceased, _) = PersonDocumentRelationType.objects.get_or_create(
name="Mentioned (deceased)"
)
join.doc_date_standard = "1310/1312"
join.save()
PersonDocumentRelation.objects.create(
person=person, document=join, type=deceased
)

person_admin = PersonAdmin(model=Person, admin_site=admin.site)
assert person_admin.active_dates(person) == standard_date_display(
document.doc_date_standard
)
assert person_admin.deceased_mention_dates(person) == standard_date_display(
join.doc_date_standard
)


@pytest.mark.django_db
class TestNameInlineFormSet:
Expand Down
20 changes: 17 additions & 3 deletions geniza/entities/tests/test_entities_metadata_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,17 @@ def test_person_iter_dicts(person, person_diacritic, person_multiname, document,
person=person_diacritic, place=fustat, type=roots
)

person.documents.add(document)
person.documents.add(join)
person_multiname.documents.add(document)
document.doc_date_standard = "1200/1300"
document.save()
PersonDocumentRelation.objects.create(person=person, document=document)
PersonDocumentRelation.objects.create(person=person_multiname, document=document)
(deceased, _) = PersonDocumentRelationType.objects.get_or_create(
name="Mentioned (deceased)"
)
join.doc_date_standard = "1310/1312"
join.save()
PersonDocumentRelation.objects.create(person=person, document=join, type=deceased)

person.tags.add("test")
person.tags.add("example")
person_multiname.tags.add("test")
Expand Down Expand Up @@ -128,6 +136,12 @@ def test_person_iter_dicts(person, person_diacritic, person_multiname, document,
assert "Mosul" in export_data.get("home_base")
assert "test" in export_data.get("tags")
assert "example" in export_data.get("tags")
assert export_data.get("active_date_range") == standard_date_display(
"1200/1300"
)
assert export_data.get("deceased_date_range") == standard_date_display(
"1310/1312"
)
elif str(pers) == str(person_multiname):
assert export_data.get("related_people_count") == 0
assert export_data.get("related_documents_count") == 1
Expand Down
70 changes: 66 additions & 4 deletions geniza/entities/tests/test_entities_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,14 +439,26 @@ def test_date_str(self, person, document):
person.save()
assert person.date_str == standard_date_display("1255")

def test_solr_date_range(self, person, document):
def test_solr_date_range(self, person, document, join):
# no date: returns None
assert not person.solr_date_range()
# document dates: should use those
document.doc_date_standard = "1200/1300"
document.save()
PersonDocumentRelation.objects.create(person=person, document=document)
assert person.solr_date_range() == "[1200 TO 1300]"

# should NOT include mentioned (deceased)
(deceased, _) = PersonDocumentRelationType.objects.get_or_create(
name="Mentioned (deceased)"
)
join.doc_date_standard = "1310/1312"
join.save()
PersonDocumentRelation.objects.create(
person=person, document=join, type=deceased
)
assert person.solr_date_range() == "[1200 TO 1300]"

# person date override
person.date = "1255"
person.save()
Expand All @@ -455,13 +467,24 @@ def test_solr_date_range(self, person, document):
def test_total_to_index(self, person, person_multiname):
assert Person.total_to_index() == 2

def test_index_data(self, person, person_multiname, document):
def test_index_data(self, person, person_multiname, document, join):
document.doc_date_standard = "1200/1300"
document.save()
(pdrtype, _) = PersonDocumentRelationType.objects.get_or_create(name="test")
PersonDocumentRelation.objects.create(
person=person, document=document, type=pdrtype
)

# these dates should be ignored (deceased)
(deceased, _) = PersonDocumentRelationType.objects.get_or_create(
name="Mentioned (deceased)"
)
join.doc_date_standard = "1310/1312"
join.save()
PersonDocumentRelation.objects.create(
person=person, document=join, type=deceased
)

tags = ["testtag", "tag2"]
for t in tags:
person.tags.add(t)
Expand All @@ -478,9 +501,10 @@ def test_index_data(self, person, person_multiname, document):
index_data = person.index_data()
assert index_data["url_s"] == person.get_absolute_url()
assert index_data["has_page_b"] == True
assert index_data["documents_i"] == 1
assert index_data["documents_i"] == 2
assert index_data["people_i"] == index_data["places_i"] == 0
assert index_data["document_relation_ss"] == [str(pdrtype)]
assert str(pdrtype) in index_data["document_relation_ss"]
assert str(deceased) in index_data["document_relation_ss"]
assert index_data["tags_ss_lower"] == tags
assert index_data["date_dr"] == person.solr_date_range()
assert index_data["date_str_s"] == person.date_str
Expand All @@ -495,6 +519,44 @@ def test_index_data(self, person, person_multiname, document):
in index_data["other_names_ss"]
)

def test_active_date_range(self, person, document, join):
# these dates should be used (active)
document.doc_date_standard = "1200/1300"
document.save()
(pdrtype, _) = PersonDocumentRelationType.objects.get_or_create(name="test")
PersonDocumentRelation.objects.create(
person=person, document=document, type=pdrtype
)
# these dates should be ignored (deceased)
(deceased, _) = PersonDocumentRelationType.objects.get_or_create(
name="Mentioned (deceased)"
)
join.doc_date_standard = "1310/1312"
join.save()
PersonDocumentRelation.objects.create(
person=person, document=join, type=deceased
)
assert person.active_date_range == document.doc_date_standard

def test_deceased_date_range(self, person, document, join):
# these dates should be ignored (active)
document.doc_date_standard = "1200/1300"
document.save()
(pdrtype, _) = PersonDocumentRelationType.objects.get_or_create(name="test")
PersonDocumentRelation.objects.create(
person=person, document=document, type=pdrtype
)
# these dates should be used (deceased)
(deceased, _) = PersonDocumentRelationType.objects.get_or_create(
name="Mentioned (deceased)"
)
join.doc_date_standard = "1310/1312"
join.save()
PersonDocumentRelation.objects.create(
person=person, document=join, type=deceased
)
assert person.deceased_date_range == join.doc_date_standard


class TestPersonSolrQuerySet:
def test_keyword_search(self):
Expand Down
Loading

0 comments on commit 4609eb4

Please sign in to comment.