For loop needs user interaction

Ok I am hitting a wall in a scenario I think I do not quite understand.

Senario - I am building a stock control app. It has the ability to purchase products in a grouping called orders. I am at the point where the app will receive a delivery in and the user is reconciling the delivery (matching orders to deliveries - correct products per order, correct product qtys, no damaged goods etc). I currently have no model to hold the reconciliation action so was managing the user activity of matching order products and qtys via a Json container. This works well and I can pass the completed reconciliation to a view called receive_delivery. receive_delivery has to loop through one or more orders, and each order can have one or more products, and each order can be a standard order or custom order. So what I was trying to do is begin a loop within the received_delivery view. If an order is a standard order pass a list of its products and the reconciliation decisions (qty counts and notes) the user made on the reconciliation page, to a function that would called handle_standard_order. This function/view handles one order at a time. handle_standard_order will then to loop through each product from the Json it received and render a page that asks the user where each product should reside (in a building and on a shelf etc). Once this list of products is stored, move to the next list of products which receive_delivery passes on a return of store of order completed that includes the storage location decisions the user just made.

This sounds more complicated that it is. However the point is the data flow starts at a page feed from one view. On submission the data is not written to a model, but rather passed in a Json container that is sent to a view which has a loop within it to process the incoming Json. To complete the loop data must leave the receive_delivery view in small subsets into other helper view/function, its return sets off the next subset it has to process, until no more subsets exist within the receive_delivery main loop, at which time the main loop within receive_delivery ends, and the view renders a page back at a orders home page.

So while each subset of data is processed by the helper function, the main loop within receive_delivery is paused waiting for the subset returns.

Within the helper function I want to ask for User input to feed the decisions of storing products. Each subset return from handle_standard_order to receive_delivery has these user feed decisions in it, receive_delivery takes each return applies these to the model and starts the next subset if one exists, until no more subsets are in the for condition.

Issue: Data enters the view receive_delivery in Json format just fine, and a for loop of the orders is created. if the data needs to leave receive_delivery to (in this example its a standard order that needs storage locations confirmed by user input) a subset of products is generate and Json is passed to a helper function handle_standard_order.

The subset of the original Json is passed between receive_delivery and handle_standard_order seems to happen without issue.

The problem occurs when handle_standard_delivery needs to render an html page to ask the user for input.

No matter how I write receive_delivery view or handle_standard_order function the render within the handle_standard_order view never fires. So the User is never prompted for input, and thus no decisions about storage locations is made.

handle_standard_order simply carries on looping and then returns to receive_delivery, which completes its loop without the correct returns then fires it last render and throws the user back to a list of orders (the orders home page, which is where I want them to go once this exercise is actually complete).

If I write both receive_delivery and handle_standard_order and do not write in any renders to get user input, but simply make arbitrary storage location decisions based upon storage locations that exist within the model. the for loops work without issue.

So my question is. Can you ask for User input in the middle of multi loop data flow, specifically if the render happens in a helper function to the main view fired? or do I need to handle all user inputs before any view loop fires?

Kind regards

Duncan

I asked ChatGPT the question and this is it’s reply:

You’re facing a common challenge when dealing with workflows that involve both user interaction and complex data processing in Django. Let’s break down your scenario and address the critical question about asking for user input during a multi-step process.

Understanding the Flow:

  1. Reconcile Orders (initial page):
  • User starts by reconciling deliveries with orders.
  • Data is collected and sent to receive_delivery.
  1. Receive Delivery:
  • Processes the orders and products based on reconciliation.
  • Needs to pause for user input on storage decisions.
  • You expect to send control to handle_standard_order for this user input.
  1. Handle Standard Order:
  • Displays a form or page asking the user for storage locations.
  • Once the user provides input, you want to return control to receive_delivery to continue processing.

Core Issue:

  • Rendering and User Input Mid-Process:
    • In a web request-response cycle, once you render a page (using render()), you cannot “pause” the function and resume it with user input.
    • Django views handle a single HTTP request and return a single response. There’s no built-in mechanism to “wait” for user input within the same view cycle.

Solution: Restructure the Workflow

To handle user input in a looped process:

1. Step-by-Step Approach with Intermediate States:

  • Break down the process into discrete steps, with each step represented by its own view.
  • Use sessions or temporary models to store intermediate data between requests.

2. Implementation Outline:

  1. Initial Request Handling (receive_delivery):
  • Process initial JSON data.
  • Store the reconciliation data and the current state (e.g., which order/product needs user input) in the session or a temporary model.
  • Redirect to handle_standard_order for user input.
  1. handle_standard_order:
  • Retrieve the current state from the session.
  • Render a form for the user to input storage decisions.
  • On form submission, validate and save the user’s input.
  • Update the session or temporary model to reflect the next step or product to handle.
  • Redirect back to either the same handle_standard_order (if more products need input) or receive_delivery to continue processing.

Annoyingly, I think its right. My concern with this approach to Break down the process into discrete steps, with each step represented by its own view. Is that the user has to click more times that I wanted them to. I really wanted this to feel like the app was helping the User and not making you work harder for the same result.

Unless there are any better ideas I am of to write in more models and views.

Kind regards

Duncan

Duncan,
Fundamentally Chat-GPT is correct, but this isn’t a Django Issue - it is how HTTP works - your idea of doing a for-loop in a view and rendering new pages to get new data from the user simply would never work.

Fundamentally HTTP is send/response - where the send is user interaction on the browser and that can only make a new GET or POST request to the server and the server can either consume that request silently or respond with some form of content (a new webpage/or maybe json data).

You will need to refactor your workflow - so when you need user interaction, you need someway to store/mark your existing progress, and then do a return render(…) to push the web page back to the user (with maybe hidden fields or similar that identify your progress so far.

When the user confims the right course of action and hits the button - that will trigger a new view instance on the server - and the view can restart the progress from where it left off.

So in the case where you need user interaction on each entry there wont be a for loop then it will a view that simply processes the next item and then sends a form to confirm the next item.

To avoid too much interaction - you could :
a single view which identifies and processes everything that doesn’t need interaction, and identifies all those orders which need further input.
That view then redirects to a Updatable List View which displays all of the orders that need confirmation on a single page - with a simple tick box on each order to confim the ones that the users wants to progress and a submit button that goes to a new view that can read those tick boxes one at a time.

1 Like