在Django中更好的Ajax实现方式

4 投票
4 回答
2143 浏览
提问于 2025-04-15 14:40

前几天,我为我正在开发的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 个回答

3

无论如何,你至少需要两样东西:

  1. 你的JavaScript代码来发起请求(这个你已经有了)

  2. 服务器端的代码来处理请求(这就是你的视图和网址配置)

这完全没有什么“黑科技”的成分。

第三样东西,你的模板文件,是可选的——但通常来说这是个好习惯。你想把标记(也就是网页的结构)和代码分开,原因有很多。

所以我觉得你想的方向是对的。继续加油!

4

我虽然来得有点晚,但想记录一下如何结合和调整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">&nbsp;</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);
           }
        });
    });

希望这对一些人有帮助。如果有帮助,请留下评论!

5

这要看你想做什么。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请求的话,只返回需要更新的部分。在你的情况下,就是表格的视图。

撰写回答