从 Django 模型中使用 Ajax 获取模态数据

Posted

技术标签:

【中文标题】从 Django 模型中使用 Ajax 获取模态数据【英文标题】:Fetch modal data with Ajax from Django Model 【发布时间】:2020-07-26 01:21:27 【问题描述】:

很抱歉重复这个问题,以及 Ajax 集成,因为它的主题非常广泛,但我就是想不通。

我有一个包含 4k+ 行数据的 html 表,每一行都有一些基本信息,如姓名、地址、姓氏、电话和一个按钮,该按钮触发一个引导模式,其中包含附加数据,如电话 2、地址 2、等等

我的问题是,因为我的模式位于这样的 for 循环中 -

<tbody>
    % for opp in optika %
        <tr>
            <td> opp.example </td>
            <td> opp.some_field </td>
            <td>            
                <button id="testbtn" type="button" class="btn btn-success btn-sm btn-detail"
                    data-toggle="modal"
                    data-target="#detalji_modal opp.pk "
                    Detalji
                </button>
            </td>
...
        </tr>
    % include "opportunity/partials/_detalji_modal.html" %
    % endfor %
</tbody>

这是模态细节 -


<div class="modal fade bd-example-modal-lg" tabindex="-1" role="dialog"
     id="detalji_modal opp.pk "
     aria-labelledby="detalji_modalLabel">
    <div class="modal-dialog modal-lg" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="detalji_modalLabel">Detalji</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="modal-body" id="">
                <div class="container-fluid">
                    <h5> opp.... </h5>
                    <p> opp.....title </p>
                    ...
                </div>
            </div>
            <div class="modal-footer">
                <p style="margin-right: auto">Zahtev uneo/la :  opp.... </p>
                ...
                ...
                <button type="button" class="btn btn-outline-primary" data-dismiss="modal">
                    Close
                </button>
            </div>
        </div>
    </div>
</div>

我也会通过视图:

@login_required(login_url='registration/login')
def OptikaList(request):
    user_groups = request.user.groups.all()
    optika_svi = OpportunityList.objects.all().defer(
        ...
    ).filter(opp_type__exact='optika').exclude(opp_status='zakazan', is_locked=True).order_by('eluid',
                                                                                              '-opp_status').exclude(
        opp_status='odustao')
    optika = [o for o in list(optika_svi)]

    counter = 1000

    context = 
        'optika': optika[:counter],
        'broj_poslova': counter,
        'ukupno_poslova': optika_svi.count(),
        'user_groups': user_groups,
    

    #Ajax is not used for now, since idk how to implement it right.
    if request.is_ajax():
        data = 
            'rendered_table': render_to_string('opportunity/get_more_tables.html', context=context,
                                               request=request)

        return JsonResponse(data)

    return render(request, 'opportunity/opp_optika.html', context)

这是我的 ajax 调用,一团糟 -

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script>
    $(document).ready(function () 

        // Our ajax function. Specifically declared as we are
        // using it in multiple places
        let ajax_function = function () 
            fetch_modal();
            page_changing = false;
            $.ajax(
                url: '% url 'opportunity:optika' %',
                type: "get",
                cache: true,
                data_type: 'html',

                success: function (data) 
                    console.log("Ajaxed");
                    var page = dt.page(); // save page we are on
                    var order = dt.order(); // save ordering
                    var search = dt.search();
                    var page_length = dt.page.len();
                    dt.destroy(); // put table back to new

                    $('#dataTable').find('tbody').empty().append(data.rendered_table);
                    dt = $('#dataTable').DataTable(table_options); // Re-init datatable
                    dt.order(order); // Put back our ordering
                    dt.search(search);
                    dt.page.len(page_length);
                    dt.page(page).draw('page'); // Draw the page
                    dt.draw(false); // Put in our ordering an all the stuff

                    if (focused_search) 
                        $('input[type=search]').first().focus();
                        console.log('focused');
                    
                    focus_set();
                    focus_lost();
                    page_changer();
                    set_detail_btn();
                ,
                error: function (data) 
                    console.log("Ajax stopped!");
                
            );
        ;

        // Variables to hold our urls to the body and footer views
        let body_update_link = '% url 'opportunity:fetch_body' %';
        let footer_update_link = '% url 'opportunity:fetch_footer' %';

        // id of opportunity currently in our modal
        let modal_opp = false;

        // ajax function for getting data for modal
        let fetch_modal = function () 
            if (modal_opp) 
                $('#detalji_modal .modal-body').load(body_update_link, modal_opp.toString());
                $('#detalji_modal .modal-footer').load(footer_update_link, modal_opp.toString());
            
        ;

        // function for activating getting modal data on click on details
        let set_detail_btn = function () 
            $('.btn-detail').click(function () 
                modal_opp = $(this).data('opp');
                fetch_modal();
            );
        ;

        // Set modal_opp to false after our modal has disappeared to avoid
        // unnecessary updates of an invisible modal
        $('#detalji_modal').on('hidden.bs.modal', function (e) 
            modal_opp = false;
        );

        // A central variable for putting in table options
        let table_options = 
            // searching: false,
            // paging: false
            order: [[0, "asc"]]
        ;

        // variable holding our setInterval function so we can disable
        // it if we want to
        let my_timer;

        // variable set to true if we are currently in the filter
        let focused_search = false;

        // Set our focused_search variable if our filter has focus
        let focus_set = function () 
            $('input[type=search]').focus(function () 
                console.log('HAS FOCUS');
                focused_search = true;
                clearInterval(my_timer);
                my_timer = false;
            );
        ;

        // Reset our focused_search variable if our filter loose focus
        const focus_lost = function () 
            $('input[type=search]').blur(function () 
                    console.log('LOST_FOCUS');
                    focused_search = false;
                ,
                function () 
                    console.log('LOST_FOCUS');
                    conditional_timer_restart();
                    focused_search = false;
                
            );
        ;

        // Restart our timer
        const conditional_timer_restart = function () 
            if (!my_timer) 
                my_timer = setInterval(ajax_function, 2000);
            
        ;

        // variable set to true if we have changed paging
        // needed when we click on our paging select so
        // our timer restart raliably
        let page_changing = false;

        // Function to add some behaviour to our pager
        // Will stop reloading page if we click on that select
        // Will restart the reloading cycle automatically after 5
        // seconds
        const page_changer = function () 
            $('select[name=dataTable_length]').click(function () 
                console.log('Page changer init');
                if (page_changing) 
                    page_changing = false;
                 else 
                    clearInterval(my_timer);
                    my_timer = false;
                    setTimeout(conditional_timer_restart, 5000);
                
            );
            $('select[name=dataTable_length]').change(function () 
                console.log('Page changer done');
                page_changing = true;
                my_timer = setInterval(ajax_function, 5000);
            );
            $('select[name=dataTable_length]').blur(function () 
                console.log('Page changer lost focus');
                if (!my_timer) 
                    my_timer = setInterval(ajax_function, 5000);
                

            );

        ;
        set_detail_btn = function () 
            $('.btn-detail').click(function () 
                modal_opp = $(this).data('opp');
                fetch_modal();
            );
            $('.btn-detail').hover(
                function () 
                    console.log('hovered');
                    clearInterval(my_timer);
                    my_timer = false;
                ,
                function () 
                    console.log('hoveroff ');
                    conditional_timer_restart();
                
            );
        ;

        // Our intial init of the table
        let dt = $('#dataTable').DataTable(table_options);
        focus_set();
        focus_lost();
        page_changer();
        set_detail_btn();
        // my_timer = setInterval(ajax_function, 1000);

    );

</script>


views.py 中的 fetch_body 和 fetch_footer 函数 -

def fetch_body(request):
    id = list(request.GET.keys())[0]
    opp = OpportunityList.objects.get(pk=id)

    return HttpResponse(
        render_to_string('opportunity/partials/_modal_body.html', context='opp': opp, request=request))


def fetch_footer(request):
    id = list(request.GET.keys())[0]
    opp = OpportunityList.objects.get(pk=id)

    return HttpResponse(
        render_to_string('opportunity/partials/_modal_footer.html', context='opp': opp, request=request))

页面本身需要 5 秒以上的时间来加载,而且它有超过 20mb 的数据,这是一个巨大的杀伤力。

基本上我需要在模态打开/按钮(testbtn)点击时获取模态主体(数据)。

或者加载详细信息(模态)仅用于显示具有分页的对象。

而且由于我对 Ajax(它仍然让我感到困惑)和 jQuery 不太好,有人可以解释一下最好的方法(示例会很棒!)。

谢谢!

【问题讨论】:

有很多例子,随便选一个。 ***.com/questions/20306981/… 例如。您的时间问题可能是因为您多次获取对象/您的模板 for 循环不断进行查找,这会花费时间。 docs.djangoproject.com/en/3.0/ref/models/querysets/… 看看那个和values/values_list。最后但并非最不重要的一点是,我建议对代码中的所有内容(属性、变量、名称等)使用英语。你偷了你的项目变得更大的机会...... 我觉得这个链接没用,我已经看过了。我在那里找不到我的问题的好例子。预取相关很好,但我从 db 视图中提取数据,它不是托管的,只有 CharFields,所以这里没有预取相关。我也更喜欢英文,但是这个是可以理解的,因为我删除了所有不必要的代码。 请发布您的 Ajax 调用(js)。也许创建一个单独的 url 和函数来理解这个概念会更容易。想法是在第一个视图中加载一些数据,然后使用 Ajax 调用获取更多数据。一种方法是每次用户打开模式时触发 Ajax 调用,并且在模式中有更多通过 Ajax 加载的数据。另一种方法是只加载 10 个对象,然后滚动加载下一个 10,依此类推。顺便说一句'optika': optika[:counter] 没有意义,如果您想限制查询,请在获取对象时执行此操作。您示例中的计数器始终为 1000?为什么是 int()? 我添加了当前未使用的 ajax 调用。是的,我理解理论上的逻辑,只是不知道如何在我的代码中实现它。 【参考方案1】:

事实证明,Ajax 并不难理解。

所以基本上没有正确答案,你应该选择最适合你的选项。

如前所述,此链接How do I integrate Ajax with Django applications? 为初学者提供了很好的详细说明。

【讨论】:

以上是关于从 Django 模型中使用 Ajax 获取模态数据的主要内容,如果未能解决你的问题,请参考以下文章

Django + ajax + 模态表单 bootstrap5.如何让它发挥作用?

如何从 Bootstrap 的模态形式发布数据?

Django - Ajax 注册

Django:使用forms.py更新现有模型中的单个字段

将 Django 和 Bootstrap 5 Modal 与 Ajax 结合使用

如何构建 django ajax 模态弹出表单(带有服务器端表单)?