From 2bbc9a16adfb2a79109f6e3ae06b6ca016c8e746 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Sat, 15 Apr 2023 11:36:18 +0200 Subject: [PATCH] Fix deduplicating books that are on a shelf or in a list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously when the deduplicate_book_data script tried to merge an edition that was on a shelf or in a list then it would fail because when the canonical book was added to the shelf or the list then it wouldn’t set the extra fields of the linking table for the “through” model of the field. These would end up defaulting to NULL, but that is not valid for some of the fields in ShelfItem and ListItem so postgres wouldn’t accept it. To fix that, this patch makes it skip updating fields that have a non-autogenerated linking table. The linking table would appear as a separate model anyway so the book will be moved via that instead. Fixes: #2817 --- .../management/commands/deduplicate_book_data.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/bookwyrm/management/commands/deduplicate_book_data.py b/bookwyrm/management/commands/deduplicate_book_data.py index 5ca8496b0..4519d2cff 100644 --- a/bookwyrm/management/commands/deduplicate_book_data.py +++ b/bookwyrm/management/commands/deduplicate_book_data.py @@ -1,7 +1,7 @@ """ PROCEED WITH CAUTION: uses deduplication fields to permanently merge book data objects """ from django.core.management.base import BaseCommand -from django.db.models import Count +from django.db.models import Count, ManyToManyField from bookwyrm import models @@ -12,6 +12,16 @@ def update_related(canonical, obj): (r.remote_field.name, r.related_model) for r in canonical._meta.related_objects ] for (related_field, related_model) in related_models: + # Skip the ManyToMany fields that aren’t auto-created. These + # should have a corresponding OneToMany field in the model for + # the linking table anyway. If we update it through that model + # instead then we won’t lose the extra fields in the linking + # table. + related_field_obj = related_model._meta.get_field(related_field) + if isinstance(related_field_obj, ManyToManyField): + through = related_field_obj.remote_field.through + if not through._meta.auto_created: + continue related_objs = related_model.objects.filter(**{related_field: obj}) for related_obj in related_objs: print("replacing in", related_model.__name__, related_field, related_obj.id)