I've given you enough to get started, but you will have to learn some jquery and javascript on your own to handle the messages you're getting from polling. It's not that bad; there are numerous examples you can use on stack overflow and all over the internet. Hope this helps.
add to models
:
class UserCalculationUpdate(models.Model)
user = models.ForeignKey(User)
stage = models.SmallIntegerField(default=0, max_length=1)
message = models.TextField(default='')
_stage_dict = {-1: 'Failed.', 0: 'On stage 1 of 3', 1: 'On stage 2 of 3',
2: 'On stage 3 of 3', 3: 'Calculation Complete!'}
def get_stage(self):
return self._stage_dict[self.stage]
run python manage.py makemigrations
, debug any mistakes I've made, and run python manage.py migrate
.
import your new model and json stuff and edit your view
:
from django.http import JsonResponse
from my_app.models import UserCalculationUpdate
# I'd rename your view to something else.
def form(request):
if request.method == 'POST'
form = MyForm(request.POST)
if form.is_valid():
form = convert_form_to_model(form.cleaned_data, MyModel)
"""
looks to see if there is a UserCalculationUpdate object
corresponding to the present user. If not, it creates one
and sets obj.stage = 0 and sets created = True, otherwise,
it sets obj.stage = 0 for the object already in the db
and sets created = False
"""
obj, created = UserCalculationUpdate.objects \
.update_or_create(user=request.user,
defaults={'stage':0})
result1, success, message = step_one_calc(form)
# storing the progress in our new model, success should be
# a boolean
if success:
obj.update(stage=1)
else obj.update(stage=-1, message=message)
return HttpResponse() # whatever you want to happen when fails
result2, success, message = step_two_calc(result1, success)
if success:
obj.update(stage=2)
else obj.update(stage=-1,
message=message)
return HttpResponse() # whatever you want to happen when fails
"""
. . . and so on . . .
"""
return HttpResponseRedirect(reverse('my_app:results', args(form.id,)))
else:
return render(request, 'my_app/form.html')
else:
form = MyForm()
render(request, 'my_app/form.html')
def poll_view(request):
user_calc_update = UserCalculationUpdate.objects \
.filter(user=request.user):
if len(user_calc_update) != 0:
stage_message = user_calc_update[0].get_stage()
results_message = user_calc_update[0].message
# 0 is incomplete 1 is complete
completion_status = 0 if user_calc_update[0].stage == 3 else 1
return JsonResponse({
'message': f'{stage_message} {results_message}',
'completion_status': completion_status
})
except UserCalculationUpdate.DoesNotExist:
return JsonResponse({
'message': 'Beginning Calculations',
'completion_status': 0
})
add to your urls
:
url(r'^calculation_poll/$', view.poll_view, name='poll_view')
make sure to add {% load url %}
to the top of your template,
add jquery by including <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
in your header if you haven't already, and add this script someonwhere in your template:
<script>
// $('#id') is the jquery selector syntax for selecting an element by its id
// and manipulating it.
$('#calc_submit_button_id').click(function(){ //adding an onclick trigger
$('#loading').show(); //the 'loading' element is where you want your //information about your progress to show, this can
// a modal or a bootstrap alert or whatever you like.
// the .show() method removes any 'display:none' or
// 'display: hidden' from the style of the 'loading'
// element.
pollingFunction = $.ajax({
dataType: "json",
url:"{% url "poll_view" %}",
data: '',
success: function (message){
/* use console.log() and look at the console using inspect element
(ctrl + shift + i in chrome, right click + Q in firefox) to
examine the structure of your message
*/
console.log(message)
# Some code that decides what to do with message
if (you wish to display the message and poll again)
{
//adds message to ('#loading'), should make it prettier, but
//serves our purpose for now
('#loading').empty()
('#loading').html('<h3>' + JSON.stringify(message) + '</h3>')
//wait ten seconds, poll again
setTimeout(pollingFunction, 10000)
}
else(you wish to end polling and hide the ('#loading') element)
{
$('#loading').hide();
}
},
error: function(jqXHR){
console.log(jqXHR)
('#loading').html('<h3>Oh no, something awful happened, better check the logs.</h3>')
}
});
});
</script>