Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
4 of 5 tasks
rrauenza opened this issue Aug 16, 2018 · 2 comments
Closed
4 of 5 tasks

Comments

@rrauenza
Copy link

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'"

@rrauenza
Copy link
Author

rrauenza commented Aug 20, 2018

I wonder if the minimized ask would be to have DRF's stock ListSerializer somehow have a way to detect that we're looking at a queryset that needs to be resolved into an item. The DRF-bulk bug suggests this code, but this doesn't handle both cases where self.instance might actually be an instance.

Or some way to make bulk update easier to implement outside the project and not likely to break as DRF moves forward.

      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)
            except ValidationError as exc:
                errors.append(exc.detail)
            else:
                ret.append(validated)
                errors.append({})

@velis74
Copy link

velis74 commented Dec 23, 2018

I have also identified this issue a couple of days ago, for the same reasons as @rrauenza .
The fix mentioned works for me too.

EagerBeager added a commit to infolabs/django-rest-framework-bulk that referenced this issue Jan 11, 2019
2. Add validate bulk update validation hook
3. Bugfix: Error after bulk add (POST) in API view
@encode encode locked and limited conversation to collaborators Mar 8, 2021

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants