【问题标题】:Django: POST form with status view (ajax?)Django:带有状态视图的 POST 表单(ajax?)
【发布时间】:2017-11-16 04:26:48
【问题描述】:

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

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

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

所以我要求有人帮我做这件事。

例如在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')

【问题讨论】:

  • 结合 Ricky 和 ​​Nam 的答案,这就是你需要的一切。
  • @DragonBobZ 能否提供一个具体的例子
  • @SamNeuron 我下班回家后也许能帮上忙。
  • @DragonBobZ 请问我真的需要帮助吗 :)
  • @SamNeuron 你去。我很肯定我犯了一些你必须调试的错误,因为我没有使用 IDE。

标签: python ajax django python-3.x


【解决方案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】:

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

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

    【讨论】:

    • 对不起,我不太明白这一点。 save() 是什么,progess()fetchprogress 是什么
    • 这些是伪代码。 save() 表示 just save the progress to a global variable or a database or redisfetchprogress() 表示 somehow get it back.
    • 我知道那是伪代码。 send_message_to_user_waiting_screen 也是伪代码。我的问题是如何实际上编写一个执行此操作的函数...
    • 真的取决于你现有的代码。但是请查看此示例:stackoverflow.com/questions/26514583/…
    【解决方案3】:

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

    调用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 = "loading" 的 html(正如我提到的)

    【讨论】:

    • 对不起,我不明白这一点。我真的需要一个更具体的例子来说明这一切是如何运作的......
    猜你喜欢
    • 2012-05-23
    • 2015-02-03
    • 2012-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-09
    • 2012-05-20
    相关资源
    最近更新 更多