Skip to content

Bulk patch fails with unique_together models #57

Open
@melinath

Description

@melinath

I ran into an issue with a model I was trying to bulk patch that also has a unique_together constraint. Traceback is below. The issue here is that the UniqueTogetherValidator expects to be called from a serializer with a single related instance (i.e. a normal update serializer). But the serializer is in fact instantiated with a queryset.

TBH I don't entirely understand why serializer.instance is being set to a queryset. But anyway.

Traceback (most recent call last):
  File ".../django/core/handlers/base.py", line 149, in get_response
    response = self.process_exception_by_middleware(e, request)
  File ".../django/core/handlers/base.py", line 147, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File ".../django/views/decorators/csrf.py", line 58, in wrapped_view
    return view_func(*args, **kwargs)
  File ".../rest_framework/viewsets.py", line 87, in view
    return self.dispatch(request, *args, **kwargs)
  File ".../rest_framework/views.py", line 466, in dispatch
    response = self.handle_exception(exc)
  File ".../rest_framework/views.py", line 463, in dispatch
    response = handler(request, *args, **kwargs)
  File ".../rest_framework_bulk/drf3/mixins.py", line 79, in partial_bulk_update
    return self.bulk_update(request, *args, **kwargs)
  File ".../rest_framework_bulk/drf3/mixins.py", line 73, in bulk_update
    serializer.is_valid(raise_exception=True)
  File ".../rest_framework/serializers.py", line 213, in is_valid
    self._validated_data = self.run_validation(self.initial_data)
  File ".../rest_framework/serializers.py", line 557, in run_validation
    value = self.to_internal_value(data)
  File ".../rest_framework/serializers.py", line 593, in to_internal_value
    validated = self.child.run_validation(item)
  File ".../rest_framework/serializers.py", line 409, in run_validation
    self.run_validators(value)
  File ".../rest_framework/fields.py", line 498, in run_validators
    validator(value)
  File ".../rest_framework/validators.py", line 142, in __call__
    queryset = self.exclude_current_instance(attrs, queryset)
  File ".../rest_framework/validators.py", line 135, in exclude_current_instance
    return queryset.exclude(pk=self.instance.pk)
AttributeError: 'QuerySet' object has no attribute 'pk'

My workaround was to take advantage of the 'id' attribute that the bulk serializer keeps track of and write a custom unique_together validator.

# validators.py
from rest_framework.validators import UniqueTogetherValidator


class BulkUniqueTogetherValidator(UniqueTogetherValidator):
    def exclude_current_instance(self, attrs, queryset):
        if attrs.get('id'):
            return queryset.exclude(pk=attrs['id'])
        return queryset
# serializers.py
from .validators import BulkUniqueTogetherValidator


class ThingSerializer(serializers.HyperlinkedModelSerializer):
    <...properties>

    def get_unique_together_validators(self):
        return [BulkUniqueTogetherValidator(
            queryset=Thing.objects.all(),
            fields=('field1', 'field2'),
        )]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions