Treating a request like a subroutine

I’m relatively new to Django and web stuff in general and am struggling to get a specific user flow working in Django.

I have a collection of items that a user drops in what is basically a shopping cart. Then, when they have all their items, they have to go through them one-by-one and fill in a series of additional different data about each item. The second process takes them through a few sequential forms for each item. This second process is a separate app.

What I could do is add a button to each item in the shopping cart and have the end-user push that button for each item and add logic and whatnot to enforce rules so that they are responsible for completing that second process for each item.

But what I would like is a single button to march the end user through the second process for each item sort of like a subroutine so we never need to return to the source ‘shopping cart’ page and the end-user never forgets to do that second process.

So something like

for item in the shopping_cart:
redirect( to the first page of the second process using item )

There is something in my gut that is saying I can’t do this sort of thing in django/python and may need to do it in javascript or ajax but I don’t have enough experience to know. Thanks for your help.

I’m not sure I understand what the issue here is that you’re trying to address - or why it’s a problem.

Your view can call whatever functions it needs to call to perform whatever operations need to be performed. When a form is submitted, and you’ve finished processing the submitted data, you can redirect to any page you want.

(Side note: However you have this organized into apps is irrelevent. There’s nothing about an app that is in any way going to affect how you handle this.)

Keep in mind the flow of what’s happening here. A page is displayed. If the page contains a form, and the form is submitted, then that page redirects you to another page upon completion. What that page is, is entirely up to you.

So the specific mechanism for handling this is going to depend on how you’re managing this shopping cart and the sequence and flow of events.

Let me try to be clearer. When I push the submit button on the form, the request flows to a subroutine to process the contents of the shopping cart and that request is used to call into the app for the secondary process for the first item in the cart. When that process completes I need control to flow back to the subroutine processing the cart contents to deal with the second item in the shopping cart and start the secondary process for that item. I don’t see a way for the control to flow that way. It seems that it all must end when the secondary process completes, I can’t go back to pick up where I left off in processing in the subroutine that responds to the submit button

You’ve got to look at this as page flows.

The user pushes the submit button.

What is the next interaction that they are to perform? According to your original description:

So, they push the submit button. Is the next thing they need to do is fill out another form?

Yes, exactly. They fill out a sequential series of forms that are associated with that second application - say app.page1 through app.page5. They have to fill out app.page1 through app.page5 for each item in the cart. So, ideally, they hit submit and then for each item in the cart they are sequenced through app.page1 through app.page5

Ok. So app.page1 is just another view.

What you need to manage on the server side is what happens after app.page1 has been submitted. That’s where the management of the cart on the server is important. When the form from app.page1 is submitted, then that view needs to decide where it goes next. In this case, app.page2.

All activities in a web app occur one page at a time. Each page decides what the next page is to display.

Yes. But when I get to app.page5, how do I get back to the “for loop” and select the next item in the cart? In the code below, which is called from the submit button, I have to return the render() to start the form sequence from app.page1. Since I executed a return() I can’t come back to the for loop but if I don’t execute the return the page doesn’t render. I would like the last page (app.page5) to render app.page1 with the next item.

def submit_request( request ):
for item in cart_items:
return( render( app.page1, item_id=item.thing_id ) )

So I guess I could pass the cart_items and an index to the render() and increment the index at app.page5 and start again at page1. (Thinking out loud here). Does that make sense?

When app.page5 is done, then it examines the cart to determine where it needs to go next.

There is no “loop”, or “iteration” here. Each page determines where it needs to redirect the user to next.

So in this specific case:

App.page5 does not render app.page1. It redirects to it. App.page1 is a different view - that becomes your “next page”.

You’ve got to avoid the mindset that there’s some type of “overall controller” in charge here. When you’re working with forms on web pages, the general sequence of events is:

  • Browser requests a page (GET)
  • Server returns a page with a form.
  • Browser submits a form (POST)
  • Server processes the data submitted.
  • Server returns a redirect to tell the browser what the next page is to GET

That’s it.

So yes:

This is where not knowing what the structure is of your cart, and the lack of knowledge of the implementation details of this project, becomes an inhibiting factor. But again - you do not use a view to render another view, especially when POSTing data - you redirect the browser to that view.

Addendum: Always be aware that the http protocol is stateless. Once a view has returned a response to the browser, it (logically) ceases to exist. Each invocation of a view is a new event and needs to be handled as such. That’s why things like cookies and sessions were invented, to allow applications to maintain some degree of “state” between requests. This is a vast difference from a desktop-style application, and a difference that cannot be ignored.

Excellent. Thanks for your help. I think I have some direction here as well as an understanding of how to approach this in the proper way. I also understand from other research that I shouldn’t pass objects around in my redirects (I get it - they are not renders, thanks) rather I can pass around indices and look up specific object from all such objects in the code that generates the view.

Thanks for your help and for the quick education