dabapps / django-rest-framework-serialization-spec

DEPRECATED, see https://github.com/dabapps/django-readers instead
MIT License
11 stars 0 forks source link

Two M2M id-list fields appear to collide #57

Closed pmg103 closed 4 years ago

pmg103 commented 4 years ago

When requesting two id-lists for two M2M fields, they both end up being the same list (of the last one requested, in this case the list of report_templates)

View:

class ProductOrganisationList(SerializationSpecMixin, generics.ListAPIView):

    pagination_class = HugeLengthPagination
    permission_classes = [ProductOrganisationListPermissions]

    queryset = ProductOrganisation.objects.order_by('created')

    def get_queryset(self):
        user = self.request.user
        query_params = self.request.query_params

        queryset = super().get_queryset()

        activity_type = query_params.get('activity_type')
        if activity_type:
            queryset = queryset.filter(product__activity_type=activity_type)

        organisation = user.organisation or get_object_or_404(Organisation, id=query_params.get('organisation'))
        return queryset.filter(
            organisation=organisation
        ).filter(
            Q(product__requires_accreditation=False)
            | Q(product_variant__isnull=False)
            | Q(product__requires_accreditation=True, product__in=Product.objects.filter(user__in=organisation.admins))
        )

    serialization_spec = [
        'id',
        'number_available',
        {'product': [
            'id',
            'icon',
            'name',
            'activity_type',
            {'latest_version': [
                'id',
                {'comparison_groups': [
                    'id',
                    {'entity': [
                        'id',
                        'name',
                    ]}
                ]},
            ]},
            {'report_templates': [
                'id',
                'name',
                'credit_cost',
                'type',
                {'requires_job_level': Requires(['type'])}
            ]},
            'comparisongroupentity_set',
        ]},
        {'product_variant': [
            'id',
            'name',
            'comparison_groups',
            'report_templates',
        ]},
    ]

Output:

image

pmg103 commented 4 years ago

Here is a workaround until we fix it:

        {'product_variant': [
            'id',
            'name',
            # Plugin necessary to work around SSM bug where two M2M fields conflict:
            {'comparison_groups': ProductVariantComparisonGroups()},
            'report_templates',
        ]},
class ProductVariantComparisonGroups(SerializationSpecPlugin):
    def modify_queryset(self, queryset):
        return queryset.prefetch_related(Prefetch('comparison_groups', to_attr='_comparison_groups'))

    def get_value(self, instance):
        return [each.id for each in instance._comparison_groups]
j4mie commented 4 years ago

Maybe it only happens if there's another outer layer of nesting?

j4mie commented 4 years ago

Maybe it only happens if there's another outer layer of nesting?

Nope, tried that too and it still appears to work 🤔