Princeton-CDH / geniza

version 4.x of the Princeton Geniza Project
https://geniza.princeton.edu
Apache License 2.0
11 stars 2 forks source link

WIP person-person relations list (#1595) #1596

Open blms opened 1 month ago

blms commented 1 month ago

Hi @rlskoeser,

Sorry for the long-winded explanation here, but this one is a Django data modeling doozy! Take however much time you need until you have the bandwidth to take a look at it; plenty else for me to work on in the meantime.


I've been working on this view to show all people related to a person via Person.relationships, an asymmetrical, self-referential, many-to-many through field. We want a list of each of a person's relationship objects from the intermediary table so we can display the relation type and notes. Listing person.relationships.all() only brings up a queryset of Person entries, so to get the list of relationship objects I use person.to_person.all().

However, person.to_person.all() does not in fact capture all related people. There is another set, person.from_person.all(), that may contain relationships to additional people, as well as some of the same people from the to_person set. The reasons for this are as follows:

On the admin page, we get around this by displaying both lists, with a read-only list from_person.all() labeled "Related people (automatically populated)". When the relationships are entered twice a la Nahray-Elḥanan, that means they actually appear twice on the admin page. But we don't want that on this people list page; we only want each one once, we just want to make sure the full set of related people is captured.

My current implementation ignores from_person and only displays the list from to_person.all(), i.e. input manually.

Is there a way to achieve showing both using the Django ORM? Here's what I had started to do, but it still results in duplicates. Does it seem like it's on the right track and just needs deduplication?

related_people = PersonPersonRelation.objects.filter(
    Q(from_person__pk=obj.pk) | Q(to_person__pk=obj.pk)
).annotate(
    related_slug=Case(
        When(to_person__pk=obj.pk, then=("from_person__slug")),
        When(from_person__pk=obj.pk, then=("to_person__slug")),
    ),
    relation_type=Case(
        When(to_person__pk=obj.pk, then=("type__name")),
        When(from_person__pk=obj.pk, then=("type__converse_name")),
    ),
)

Maybe a simpler option would be some kind of solr index to achieve what I actually need with more flexibility?

Or does this in fact need to be a DB constraint that I overlooked, preventing the relations from being essentially entered twice?

codecov[bot] commented 1 month ago

Codecov Report

Attention: Patch coverage is 29.72973% with 26 lines in your changes missing coverage. Please review.

Project coverage is 98.65%. Comparing base (363a421) to head (ccabaa5).

Additional details and impacted files ```diff @@ Coverage Diff @@ ## develop #1596 +/- ## =========================================== - Coverage 98.83% 98.65% -0.19% =========================================== Files 238 238 Lines 13993 14029 +36 =========================================== + Hits 13830 13840 +10 - Misses 163 189 +26 ```