【发布时间】: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">×</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 不太好,有人可以解释一下最好的方法(示例会很棒!)。
谢谢!
【问题讨论】:
-
有很多例子,随便选一个。 stackoverflow.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 调用。是的,我理解理论上的逻辑,只是不知道如何在我的代码中实现它。
标签: jquery django ajax django-templates bootstrap-modal