From e941ee05e2f148e59593468fd8df86f0109e1ad3 Mon Sep 17 00:00:00 2001 From: Jitka Halova Date: Wed, 11 Mar 2026 13:40:44 +0100 Subject: [PATCH] Fix description field clash with base class Assisted by: Claude Sonnet 4 --- CHANGES/+description-field-clash.removal | 1 + .../0048_migrate_description_to_parent.py | 36 +++++++++++++++++++ pulp_container/app/models.py | 2 -- pulp_container/app/serializers.py | 8 ----- 4 files changed, 37 insertions(+), 10 deletions(-) create mode 100644 CHANGES/+description-field-clash.removal create mode 100644 pulp_container/app/migrations/0048_migrate_description_to_parent.py diff --git a/CHANGES/+description-field-clash.removal b/CHANGES/+description-field-clash.removal new file mode 100644 index 000000000..5d0f6fd82 --- /dev/null +++ b/CHANGES/+description-field-clash.removal @@ -0,0 +1 @@ +Removed `description` field from models subclassing `Distribution` to fix field clash error when using pulpcore>=3.106. \ No newline at end of file diff --git a/pulp_container/app/migrations/0048_migrate_description_to_parent.py b/pulp_container/app/migrations/0048_migrate_description_to_parent.py new file mode 100644 index 000000000..d7f0b2341 --- /dev/null +++ b/pulp_container/app/migrations/0048_migrate_description_to_parent.py @@ -0,0 +1,36 @@ +# Generated manually to migrate description fields from subclasses to parent Distribution class + +from django.db import migrations + + +def migrate_description_data_forward(apps, schema_editor): + Distribution = apps.get_model("core", "Distribution") + ContainerDistribution = apps.get_model("container", "ContainerDistribution") + ContainerPullThroughDistribution = apps.get_model( + "container", "ContainerPullThroughDistribution" + ) + + for Model in (ContainerDistribution, ContainerPullThroughDistribution): + for dist in Model.objects.all(): + if dist.description: + parent = Distribution.objects.get(pk=dist.pk) + if not parent.description: + parent.description = dist.description + parent.save(update_fields=["description"]) + + +class Migration(migrations.Migration): + + dependencies = [ + # Ensure parent field exists before copying data + ("core", "0146_distribution_description"), + ("container", "0047_containernamespace_pulp_labels"), + ] + + operations = [ + # Copy description data from subclass tables to parent Distribution table + migrations.RunPython(migrate_description_data_forward, migrations.RunPython.noop), + # Remove duplicate fields from subclasses + migrations.RemoveField(model_name="containerdistribution", name="description"), + migrations.RemoveField(model_name="containerpullthroughdistribution", name="description"), + ] diff --git a/pulp_container/app/models.py b/pulp_container/app/models.py index d4d26f834..bdb9f9702 100644 --- a/pulp_container/app/models.py +++ b/pulp_container/app/models.py @@ -834,7 +834,6 @@ class ContainerPullThroughDistribution(Distribution, AutoAddObjPermsMixin): "Defaults to unrestricted pull access." ), ) - description = models.TextField(null=True) class Meta: default_related_name = "%(app_label)s_%(model_name)s" @@ -878,7 +877,6 @@ class ContainerDistribution(Distribution, AutoAddObjPermsMixin): "Defaults to unrestricted pull access." ), ) - description = models.TextField(null=True) pull_through_distribution = models.ForeignKey( ContainerPullThroughDistribution, diff --git a/pulp_container/app/serializers.py b/pulp_container/app/serializers.py index cabdeb99c..0d62953e8 100644 --- a/pulp_container/app/serializers.py +++ b/pulp_container/app/serializers.py @@ -421,9 +421,6 @@ class ContainerDistributionSerializer(DistributionSerializer, GetOrCreateSeriali view_name="pulp_container/namespaces-detail", help_text=_("Namespace this distribution belongs to."), ) - description = serializers.CharField( - help_text=_("An optional description."), required=False, allow_null=True - ) repository_version = RepositoryVersionRelatedField( required=False, help_text=_("RepositoryVersion to be served"), allow_null=True ) @@ -487,7 +484,6 @@ class Meta: "remote", "namespace", "private", - "description", ) @@ -521,9 +517,6 @@ class ContainerPullThroughDistributionSerializer(DistributionSerializer): queryset=models.ContainerDistribution.objects.all(), required=False, ) - description = serializers.CharField( - help_text=_("An optional description."), required=False, allow_null=True - ) def validate(self, data): validated_data = super().validate(data) @@ -549,7 +542,6 @@ class Meta: "distributions", "namespace", "private", - "description", )