I'm having a problem to call multiple functions on one click submit button. I have one form which user need to attach one file (exls document), and I need one document to use for 3 functions. I need to save document, do some pandas stuff and I need to show it in html. Can I do this by putting it in class or something? I don't care how it works, just need when document submited to be saved, doing pandas staff and pandas stuff showed in html. I really need help for this, thanks in advance.
def save_exls(request):
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
newdoc = Document(docfile=request.FILES['docfile'])
newdoc.save()
return redirect('html_exls')
else:
form = DocumentForm()
documents = Document.objects.all()
context = {'documents': documents, 'form': form,}
return render(request, 'list.html', context)
def pandas_exls(request):
if request.method == "POST":
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
output = io.BytesIO()
newdoc = request.FILES['docfile']
dfs = pd.read_excel(newdoc, sheet_name=None, index_col=[0])
writer = pd.ExcelWriter(output)
for name, df in dfs.items():
#pandas stuff
done.to_excel(writer, sheet_name=name)
output.seek(0)
response = HttpResponse(
output, content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=%s' % filename
return response
else:
form = DocumentForm()
return render(request, 'list.html', {'form': form})
def html_exls(request):
if request.method == "POST":
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
output = io.BytesIO()
newdoc = request.FILES['docfile']
dfs = pd.read_excel(newdoc, sheet_name=None, index_col=[0])
writer = pd.ExcelWriter(output)
for name, df in dfs.items():
#pandas stuff for html
done.to_excel(writer, sheet_name=name)
html = done.to_html()
print(html)
output.seek(0)
response = HttpResponse(
output, content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=%s' % filename
return response
else:
form = DocumentForm()
return render(request, 'list.html', {'form': form})
CodePudding user response:
Some options you might want to explore:
- If all APIs are actually coupled to each other, you might want to transform it to a single API instead that will perform all 3. Then to still support each API individually, refactor the code so that you wouldn't have to repeat the same code in the combined API along with the individual APIs.
- On top of the HTML template, add JavaScript (AJAX) which will intercept the form submission in where you would perform the 3x HTTP POST requests to the different URLs.
- Apply Publish/Subscribe (Pub/Sub) pattern (Producer/Consumer). The idea is to subscribe the 3x URLs to resource-x. Now, publish/post the data to resource-x. The Pub/Sub system should then forward the data and call all the subscribed consumers which are the 3x URLs.
- One way is through services such as AWS SNS where you would setup a topic, subscribe the 3x URLs to that topic, and then change your form to post to that topic.
- Another way is by implementing task queueing such as Celery. Transform the 3x URLs to be Celery tasks. Then prepare a single HTTP URL which will enqueue the received requests to the 3x tasks. Then change your form to post to that HTTP URL.
- Not recommendable. This would be the simplest but is a dirty hack and is highly synchronous. Chain each view to each other in a way that after one view finishes, call the next.