Skip to content

"'QuerySet' object has no attribute 'pk'" when trying to use 'put' w/ detail=False mapping #6130

Closed
@rrauenza

Description

@rrauenza

Checklist

  • I have verified that that issue exists against the master branch of Django REST framework.
  • I have searched for similar issues in both open and closed tickets and cannot find a duplicate.
  • [?] This is not a usage question. (Those should be directed to the discussion group instead.)
  • This cannot be dealt with as a third party library. (We prefer new functionality to be in the form of third party libraries where possible.)
  • I have reduced the issue to the simplest possible case.
  • I have included a failing test as a pull request. (If you are unable to do so we can still accept the issue.)

Steps to reproduce

I'm trying to implement a bulk update -- The django rest framework bulk update project seems abandoned, and has a bug that I think is the same as my implementation (I'm trying to do a minimal implementation just for my project and not be dependent on the other one.)

I suspect it's a bug that came up with a recent version of drf3.

The conversation in the bug proposes subclassing the ListSerializer and rewriting to_internal_value, copying the code from the original implementation -- inserting this code into the method:

       for item in data:
            try:
                # Code that was inserted
                self.child.instance = self.instance.get(id=item['id'])
                self.child.initial_data = item
                # Until here
                validated = self.child.run_validation(item)

The issue comes down to the internals of drf passing the list as the instance in exclude_current_instance().

Here's how I started implementing mine:

class _MyRouter(routers.DefaultRouter):
    include_root_view = False
    include_format_suffixes = False

    def __init__(self, *args, **kwargs):
        self.routes = copy.deepcopy(self.routes)
        for route in self.routes:
            if isinstance(route, routers.Route) and not route.detail:
                route.mapping.update({
                    'put': 'bulk_update',
                })
                break
        super(_MyRouter, self).__init__(*args, **kwargs)

I then implemented bulk_update in my viewset - this is just the beginning of it for proof of concept:

def bulk_update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        assert not partial
        serializer = self.get_serializer(
            self.filter_queryset(self.get_queryset()),
            data=request.data,
            many=True,
            partial=partial,
        )
        # import pdb; pdb.set_trace()
        serializer.is_valid(raise_exception=True)

Stepping over is_valid() raises the AttributeError: "'QuerySet' object has no attribute 'pk'"

I'm reluctant to go and just copy a bunch of code from drf into a subclass -- surely it will break in the future.

Expected behavior

I'm hoping there is already a supported way for doing this, and if not, I'm posting this in hope it's a use case you want to consider supporting (not directly the bulk update itself, but the underlying problem of the list serializer) so that bulk updates would be easier to implement outside the project.

Actual behavior

Stepping into is_valid() eventually raises the AttributeError: "'QuerySet' object has no attribute 'pk'"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions