Browse Source
chore(hadis): normalize book edition contributors to 1 researcher and 1 editor
chore(hadis): normalize book edition contributors to 1 researcher and 1 editor
- Add normalize_edition_contributors management command to ensure every BookEdition has at most 1 researcher and 1 editor (and backfill missing ones) - Update generate_editions_and_volumes, seed_edition_researchers, and seed_edition_editors commands to create exactly 1 researcher and 1 editor per editionmaster
4 changed files with 93 additions and 49 deletions
-
6apps/hadis/management/commands/generate_editions_and_volumes.py
-
88apps/hadis/management/commands/normalize_edition_contributors.py
-
24apps/hadis/management/commands/seed_edition_editors.py
-
24apps/hadis/management/commands/seed_edition_researchers.py
@ -0,0 +1,88 @@ |
|||||
|
from django.core.management.base import BaseCommand |
||||
|
from django.db import transaction |
||||
|
from apps.hadis.models import BookEdition, BookAuthor, BookResearcher, BookEditor |
||||
|
|
||||
|
|
||||
|
class Command(BaseCommand): |
||||
|
help = "Ensure every BookEdition has exactly 1 BookResearcher and 1 BookEditor." |
||||
|
|
||||
|
def handle(self, *args, **options): |
||||
|
editions = list(BookEdition.objects.prefetch_related("researchers", "editors").order_by("id")) |
||||
|
authors = list(BookAuthor.objects.order_by("id")) |
||||
|
|
||||
|
if not editions: |
||||
|
self.stdout.write(self.style.WARNING("No BookEditions found.")) |
||||
|
return |
||||
|
|
||||
|
if not authors: |
||||
|
self.stdout.write(self.style.ERROR("No BookAuthors found.")) |
||||
|
return |
||||
|
|
||||
|
deleted_researchers = 0 |
||||
|
created_researchers = 0 |
||||
|
deleted_editors = 0 |
||||
|
created_editors = 0 |
||||
|
|
||||
|
with transaction.atomic(): |
||||
|
for idx, edition in enumerate(editions): |
||||
|
# 1. Normalize Researchers to exactly 1 |
||||
|
researchers = list(edition.researchers.all()) |
||||
|
if len(researchers) > 1: |
||||
|
# Prefer keeping one that has an author linked |
||||
|
researchers.sort(key=lambda r: (0 if r.author_id else 1, r.id)) |
||||
|
keep_r = researchers[0] |
||||
|
extra_r_ids = [r.id for r in researchers[1:]] |
||||
|
BookResearcher.objects.filter(id__in=extra_r_ids).delete() |
||||
|
deleted_researchers += len(extra_r_ids) |
||||
|
chosen_researcher_author_id = keep_r.author_id |
||||
|
elif len(researchers) == 1: |
||||
|
keep_r = researchers[0] |
||||
|
if not keep_r.author_id: |
||||
|
author_obj = authors[idx % len(authors)] |
||||
|
keep_r.author = author_obj |
||||
|
keep_r.save() |
||||
|
chosen_researcher_author_id = keep_r.author_id |
||||
|
else: |
||||
|
author_obj = authors[idx % len(authors)] |
||||
|
keep_r = BookResearcher.objects.create( |
||||
|
book_edition=edition, |
||||
|
author=author_obj, |
||||
|
) |
||||
|
created_researchers += 1 |
||||
|
chosen_researcher_author_id = keep_r.author_id |
||||
|
|
||||
|
# 2. Normalize Editors to exactly 1 |
||||
|
editors = list(edition.editors.all()) |
||||
|
if len(editors) > 1: |
||||
|
# Prefer keeping one with an author (ideally distinct from researcher author) |
||||
|
editors.sort( |
||||
|
key=lambda e: ( |
||||
|
0 if (e.author_id and e.author_id != chosen_researcher_author_id) else (1 if e.author_id else 2), |
||||
|
e.id, |
||||
|
) |
||||
|
) |
||||
|
keep_e = editors[0] |
||||
|
extra_e_ids = [e.id for e in editors[1:]] |
||||
|
BookEditor.objects.filter(id__in=extra_e_ids).delete() |
||||
|
deleted_editors += len(extra_e_ids) |
||||
|
elif len(editors) == 1: |
||||
|
keep_e = editors[0] |
||||
|
if not keep_e.author_id: |
||||
|
author_obj = authors[(idx + 1) % len(authors)] |
||||
|
keep_e.author = author_obj |
||||
|
keep_e.save() |
||||
|
else: |
||||
|
author_obj = authors[(idx + 1) % len(authors)] |
||||
|
BookEditor.objects.create( |
||||
|
book_edition=edition, |
||||
|
author=author_obj, |
||||
|
) |
||||
|
created_editors += 1 |
||||
|
|
||||
|
self.stdout.write( |
||||
|
self.style.SUCCESS( |
||||
|
f"Normalized {len(editions)} BookEditions:\n" |
||||
|
f" - Researchers: deleted {deleted_researchers} extras, created {created_researchers} missing (now {BookResearcher.objects.count()} total)\n" |
||||
|
f" - Editors: deleted {deleted_editors} extras, created {created_editors} missing (now {BookEditor.objects.count()} total)" |
||||
|
) |
||||
|
) |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue