Skip to content
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

CBV for organising code from different HTTP methods #8

Open
cipang opened this issue Sep 29, 2020 · 2 comments
Open

CBV for organising code from different HTTP methods #8

cipang opened this issue Sep 29, 2020 · 2 comments

Comments

@cipang
Copy link

cipang commented Sep 29, 2020

Many thanks for your informative guide first of all.

One of the way I use CBV is to group related GET/POST/HEAD... code together. For example:

class BookingView(View):
  def get(self, request):
    # code to show the booking
  def post(self, request):
    # code to update the booking

instead of using a bunch of if statements in a FBV like this:

def booking_view(request):
  booking = Booking.objects.get(...)
  if request.method == 'POST':
    # code to show the booking
  elif request.method == 'HEAD':
    # ...
  # show the booking...
  return render(...)

What's your opinion on that? Any suggestions in this use case can be included in your guide?

@spookylukey
Copy link
Owner

spookylukey commented Sep 29, 2020

Thanks for the question!

I agree that there is a certain kind of neatness to the CBV pattern you've highlighted. My practice is to write the code exactly as you have here in the second example. I try to keep the contents of each branch small, by moving logic into the model layer or into a Form or utility where appropriate.

The advantage of this is that common setup code between get and post becomes much easier - you can just re-use local variables. This to me is a big advantage, since there is almost always common logic, and communicating by setting variables on self is kind of ugly and harder to reason about.

The disadvantage is that you get a longer function, instead of several shorter methods. I don't worry about this too much, because I don't pay much notice to people who say "no function should be more than 5 lines long" etc. I prefer short function/methods when they are meaningful bits of logic, but not for the sake of it.

In terms of boilerplate, it's about the same.

If there isn't common logic, I might have 2 completely separate views and use require_POST and require_GET decorators. https://docs.djangoproject.com/en/3.1/topics/http/decorators/#django.views.decorators.http.require_POST

For the case where you have no common setup, but want the same URL, an interesting possibility might be to do something like this:

booking_view = dispatch_by_http_verb()

@booking_view.get
def booking_view(request):
    # do get thing

@booking_view.post
def booking_view(request):
    # do post thing

Or something similar. See https://docs.python.org/3.8/library/functools.html?highlight=singledispatch#functools.singledispatch for other inspiration on what it might look like.

Implementation of dispatch_by_http_verb is left as an exercise BTW! I'm not sure if I'd use this pattern but it might be worth exploring.

Here's another idea:

@dispatch_by_http_verb
def booking_view(request, booking_id):
   # Common setup
    booking_account = get_booking_account_from_request(request)
    booking = Booking.objects.for_account(booking_account).get(id=booking_id)
    return (booking_account, booking)

@booking_view.get
def booking_view(request, booking, booking_account):
    # do get thing

@booking_view.post
def booking_view(request, booking, booking_account):
    # do post thing

Here dispatch_by_http_verb takes the return args from the first function and passes them as parameters to the sub view functions. Perhaps a bit obfuscated?

Of course, if you really like the CBV pattern you've described, then I'd suggest you just use it :-)

@jayqi
Copy link

jayqi commented Aug 4, 2024

I had the same question and felt like this topic was conspicuously absent from the guide. I think the discussion in this thread would be a great addition.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants