在Django中更好的Ajax实现方式
前几天,我为我正在开发的Django应用写了一些AJAX代码。
我之前主要用Ruby on Rails,所以对原生JavaScript不太熟悉。
所以我根据Rails的部分视图,写了类似下面的伪代码,细节不必太在意:
1) 一个使用prototype的Ajax.Updater的JS函数('tablediv'是我想用AJAX更新的表格的ID,url指向正确的Django视图)
function updateTable(){
new Ajax.Updater('tablediv',url {params: params....etc
2) 一个Django视图,用来获取新数据填充表格:
def ajaxTable
objects = Objects.object.all...
return render_to_response('ajaxtable.html',objects)
3) ajaxtable.html其实就是Rails中的“部分视图”,基本上是一个没有<table>
和</table>
标签的表格……:
<th>{{object.data}}</th>
<td>{{object.moredata}}</td>
所以我想问的问题是:
我觉得这个方法有点不太正规,主要是因为我在网上找了很久想要的东西,最后有点疲惫就随便拼凑的。
这样做是对的吗?虽然它能正常工作,但我就是不太确定,明白吗?
4 个回答
无论如何,你至少需要两样东西:
你的JavaScript代码来发起请求(这个你已经有了)
服务器端的代码来处理请求(这就是你的视图和网址配置)
这完全没有什么“黑科技”的成分。
第三样东西,你的模板文件,是可选的——但通常来说这是个好习惯。你想把标记(也就是网页的结构)和代码分开,原因有很多。
所以我觉得你想的方向是对的。继续加油!
我虽然来得有点晚,但想记录一下如何结合和调整d0ugal提出的解决方案,这样可以让模板代码更简洁。
我有一个模型用来表示联系人。
获取一个联系人信息的(通用)视图大致是这样的:
def contcactperson_detail_view(request, name):
try:
person = ContactPerson.objects.get(slug=name)
except:
raise Http404
if request.is_ajax():
return contcactperson_detail_view_ajax(request, person)
return list_detail.object_detail(
request,
queryset = ContactPerson.objects.all(),
object_id = person.id,
template_object_name = "contactperson",
)
@render_to('cms/contactperson_detail_ajax.html')
def contcactperson_detail_view_ajax(request, person):
return {'contactperson':person, 'is_ajax':True}
处理单个联系人的视图模板叫做 contcactperson_detail_view.html
:
{% extends "index.html" %}
{% block textpane %}
<h1 id="mainheader">{{ contactperson.first_name }} {{ contactperson.family_name }} </h1>
<div class="indentation"> </div>
{% include 'cms/contactperson_detail_photo.html' %}
<div id="text_pane">
{% include 'cms/contactperson_detail_textpane.html' %}
</div>
{% endblock %}
它包含了两个子模板:
contactperson_detail_textpane.html
<p>{{ contactperson.description }}</p>
<ul>
<li>
<dl>
<dt>Email</dt>
<dd>
{{ contactperson.mail }}
</dd>
</dl>
</li>
<li>
<dl>
<dt>Contact Person for</dt>
<dd>
<ul>
{% for c in contactperson.categories.all %}
<li><a href="{% url category-view c.slug %}">{{ c }}</a></li>
{% endfor %}
</ul>
</dd>
</dl>
</li>
</ul>
还有 contactperson_detail_photo.html
{% with contactperson.photo.detailphoto as pic %}
{% with pic.url as pic_url %}
<div {% if not is_ajax %}id='imageContainer'{% endif %} style="float: right;padding-right:0.5em;
padding-bottom: 1em; padding-left:0.5em;clear:both;
width:{{ pic.width }}px">
<div style="width:{{ pic.width}}px">
<img style="clear:both" src="{{ pic_url }}" alt="{{ i.name }}"/>
</div>
</div>
{% endwith %}
{% endwith %}
这三个模板会在请求不是ajax的时候使用。
但是如果请求是ajax的话,contcactperson_detail_view
会返回一个视图 contcactperson_detail_view_ajax
,这个视图使用模板 contactperson_detail_ajax.html
来渲染。这个模板大致是这样的:
<h1>{{ contactperson.first_name }} {{ contactperson.family_name }}</h1>
{% include 'cms/contactperson_detail_photo.html' %}
{% include 'cms/contactperson_detail_textpane.html' %}
所以它使用了相同的子模板,但没有扩展任何内容,因此只提供了必要的标记。因为ajax视图会传递 is_ajax = True
给模板,所以可以用来调整一些小细节,比如设置正确的id属性。
不需要上下文处理器或额外的URL配置。
最后是JavaScript代码:
$("#contact_person_portlet a").click(function(event){
event.preventDefault();
$.ajax({
type: "GET",
url: event.target.getAttribute('href'),
success: function(msg){
overlay(msg);
}
});
});
希望这对一些人有帮助。如果有帮助,请留下评论!
这要看你想做什么。Ajax的应用范围很广,从谷歌地图到简单的自动补全,复杂程度和最佳方法差别很大。
不过,有一些有用的做法可以帮助你。
1) 模板层面
确保在你的TEMPLATE_CONTEXT_PROCESSORS设置中包含“django.core.context_processors.request”。这样你就可以这样做;
{% if not request.is_ajax %}
<html>
<head>
...
</head>
<body>
...
{% endif %}
actual content
{% if not request.is_ajax %}
</body>
</html>
{% endif %}
简单来说,如果这个页面是/test/,你可以通过浏览器请求获取完整内容,或者通过JavaScript请求只获取内容。网上有一篇博客详细解释了这个,但我现在找不到了。
2) 在视图中
在模板中,我们只是访问请求对象。在视图中,你可以做非常相似的事情。
def my_view(request):
if requst.is_ajax():
# handle for Ajax requests
# otherwise handle 'normal' requests
return HttpResponse('Hello world')
上面的方法其实和你现在做的没有太大区别,但可以让你重用视图,并且写得更简洁。我并不认为你现在的做法是错的或者很 hacky,但你可以写得更简洁,重用模板和视图。
比如说,你可以只用一个模板,如果是Ajax请求的话,只返回需要更新的部分。在你的情况下,就是表格的视图。