Django:带状态视图的POST表单(ajax?)

时间:2017-06-14 06:59:15

标签: python ajax django python-3.x

我有一个表单,它接受一些用户输入,发布到视图,进行一些计算,然后重定向到输出。

当计算运行时,我可以看到我的浏览器标签中的小轮子旋转,但是用户必须在他们等待的时候看着他们的表格。

我想制作各种类型的状态视图,在某些部分进行计算时,它会向用户显示有关其进度的消息,例如“在流程的第3部分”,并在完成后重定向到结果。

所以我要求有人帮助我这样做。

e.g。在views.py

def form(request):
    if request.method == 'POST'
    form = MyForm(request.POST)
        if form.is_valid():
             form = convert_form_to_model(form.cleaned_data, MyModel)
             # DO calculations
             send_message_to_user_waiting_screen('Part One Complete')
             # DO more calculations
             send_message_to_user_waiting_screen('Part two Complete')
             ....
             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')

3 个答案:

答案 0 :(得分:1)

您需要在计算过程中将进度存储在某处。

每次客户端通过GET请求进行轮询时,您都可以发送存储的进度数据。

在伪代码中:

def form(request):
    if request.method == 'POST'
    form = MyForm(request.POST)
        if form.is_valid():
             form = convert_form_to_model(form.cleaned_data, MyModel)
             # DO calculations
             save('part1 complete')
             send_message_to_user_waiting_screen('Part One Complete')
             # DO more calculations
             save('part2 complete')
             send_message_to_user_waiting_screen('Part two Complete')
             ....
             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')


#Another endpoint to respond to polling
def progress():
    return fetchprogress(uid, some other arg)

答案 1 :(得分:1)

我已经给了你足够的开始,但你必须自己学习一些jquery和javascript来处理你从轮询中得到的消息。没那么糟糕;您可以在堆栈溢出和整个互联网上使用大量示例。希望这会有所帮助。

添加到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]

运行python manage.py makemigrations,调试我所犯的任何错误,并运行python manage.py migrate

导入新模型和json内容并修改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
        })  

添加到您的urls

url(r'^calculation_poll/$', view.poll_view, name='poll_view')

确保将{% load url %}添加到模板顶部,
如果你还没有在标题中包含<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>,请添加jquery,并在模板中的某处添加此脚本:

<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>

答案 2 :(得分:0)

您不应该一直更新状态(约%)

当您调用Ajax时,只需弹出一个对话框(或某些图像,gif ...)进行处理

然后,当Ajax完成(成功或失败)时,只需将其关闭。

像:

$('#btn').click(function(){
        $('#loading').show();
        ajaxAction = $.ajax({
                dataType: "json",
                url:"some/url/",
                data: data_to_send,
                success: function (data){
                    # Some code
                    $('#loading').hide(1500);
                }
            });
    });

请记住创建id =&#34的html; loading&#34; (正如我所说)