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

Python Django:带有状态视图的POST表单(ajax?),python,ajax,django,python-3.x,Python,Ajax,Django,Python 3.x,我有一个表单,它接受一些用户输入,发布到视图,进行一些计算,然后重定向到输出 当计算运行时,我可以在我的浏览器选项卡中看到小轮子旋转,但是用户必须在等待时查看他们的表单 我想做一个排序的状态视图,当计算在某些部分进行时,它会向用户显示一条关于其进度的消息,例如“在流程的第3部分”,完成后会重定向到结果 所以我请求有人帮我做这件事 e、 g.在views.py中 def form(request): if request.method == 'POST' form = MyForm

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

当计算运行时,我可以在我的浏览器选项卡中看到小轮子旋转,但是用户必须在等待时查看他们的表单

我想做一个排序的状态视图,当计算在某些部分进行时,它会向用户显示一条关于其进度的消息,例如“在流程的第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')

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

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

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

比如:


记住用id=“loading”(正如我提到的)创建html

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

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

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

比如:


请记住使用id=“loading”(如我所述)创建html

在计算过程中,您需要将进度存储在某个地方

每次客户端通过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)

在计算过程中,您需要将进度存储在某个位置

每次客户端通过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)

我已经为您提供了足够的入门知识,但是您必须自己学习一些jquery和javascript来处理从轮询中获得的消息。没那么糟;您可以在堆栈溢出和整个internet上使用许多示例。希望这有帮助

添加到
型号中

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]
url(r'^calculation_poll/$', view.poll_view, name='poll_view')
运行
python manage.py makemigrations
,调试我犯的任何错误,然后运行
python manage.py migrate

导入您的新模型和json内容并编辑您的
视图

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
        })  
添加到您的
URL

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]
url(r'^calculation_poll/$', view.poll_view, name='poll_view')
确保将
{%load url%}
添加到模板顶部,
如果尚未添加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>

//$('#id')是jquery选择器语法,用于根据元素的id选择元素
//并操纵它。
$(“#计算提交按钮_id”)。单击(函数(){//添加onclick触发器
$(“#加载”).show();//加载”元素是您希望//显示进度信息的地方,可以
//模态警报或引导警报或任何您喜欢的警报。
//.show()方法删除任何“display:none”或
//“加载”样式中的“显示:隐藏”
//元素。
pollingFunction=$.ajax({
数据类型:“json”,
url:“{%url”轮询视图“%}”,
数据:“”,
成功:功能(消息){
/*使用console.log()并使用inspect元素查看控制台
(在chrome中按ctrl+shift+i,在firefox中右键单击+Q)以
检查消息的结构
*/
console.log(消息)
#一些决定如何处理消息的代码
如果(您希望显示消息并再次轮询)
{   
//将消息添加到(“#加载”),应使其更美观,但
//这是我们目前的目标
(“#加载”).empty()
('#load').html(''+JSON.stringify(message)+'')
//等待10秒钟,再次投票
设置超时(轮询函数,10000)
}
else(您希望结束轮询并隐藏('#loading')元素)
{
$(“#加载”).hide();
}
},
错误:函数(jqXHR){
console.log(jqXHR)
(“#加载”).html('哦,不,发生了可怕的事情,最好检查一下日志。'))
}
});
});

我已经为您提供了足够的入门知识,但是您必须自己学习一些jquery和javascript来处理从轮询中获得的消息。没那么糟;您可以在堆栈溢出和整个internet上使用许多示例。希望这有帮助

添加到
型号中

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]
url(r'^calculation_poll/$', view.poll_view, name='poll_view')
运行
python manage.py makemigrations
,调试我犯的任何错误,然后运行
python manage.py migrate

导入您的新模型和json内容并编辑您的
视图

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
        })  
添加到您的
URL

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]
url(r'^calculation_poll/$', view.poll_view, name='poll_view')
确保将
{%load url%}
添加到模板顶部,
如果尚未添加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>

//$('#id')是jquery选择器语法,用于根据元素的id选择元素
//并操纵它。
$(“#计算提交按钮_id”)。单击(函数(){//添加onclick触发器
$(“#加载”).show();//加载”元素是您希望//显示进度信息的地方,可以
//模态警报或引导警报或任何您喜欢的警报。
//.show()方法删除任何“display:none”或
//“加载”样式中的“显示:隐藏”
//元素。
pollingFunction=$.ajax({
数据类型:“json”,
url:“{%url”轮询视图“%}”,
数据:“”,
成功:功能(消息)