Opened 19 months ago

Last modified 4 months ago

#20941 new New feature

Provide a way for CBVs to be called from instances

Reported by: mjtamlyn Owned by: mjtamlyn
Component: Generic views Version: master
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

With the changes in the dispatch method to make overriding the method easier, we lost the ability to easily instantiate and call a class based view directly. There are some custom use cases where this is useful - and it's generally useful in tests. The end user perhaps has to be careful about thread safety, but nonetheless.

Ideally this would be callable after __init__() so the view instance can have some processing done before the request is known.

This would also be useful for providing better ways to test the CBVs.

Change History (3)

comment:1 Changed 19 months ago by timo

  • Triage Stage changed from Unreviewed to Accepted
  • Version set to master

comment:2 Changed 4 months ago by tomchristie

Okay, so what am I missing here?

request = self.factory.get('/')
response = MyView.as_view()(request)

What use case or functionality is this feature request trying to address that isn't covered by the above?

comment:3 Changed 4 months ago by mjtamlyn

That's not an instance! as_view() gives an opaque function with no access to the instance of the class, so we can't test parts of it individually.

The change in the dispatch method I mentioned means that the following code currently does not work as you might expect (in particular, self.args is not set):

request = self.factory.get('/')
view = MyView(**initkwargs)
response = view.dispatch(request, *args, **kwargs)

I acknowledge that this is perhaps not that different from calling as_view(), but having an API along the lines of MyView().setup_request(request, *args, **kwargs) would allow more atomic testing of class based views in a nicer fashion. Compare below:

# current
book = Book.objects.create(...)
view = BookDetail()
view.request = request
view.args = ()
view.kwargs = {'pk': book.pk}
self.assertEqual(view.get_object(), book)

# possible better version
book = Book.objects.create(...)
view = BookDetail().setup_request(request, pk=book.pk)
self.assertEqual(view.get_object(), book)

It's not a big difference, but in my opinion it's a nice one.

Note: See TracTickets for help on using tickets.
Back to Top