在开发博客系统或者是电商系统,总之,凡是带有回复、评论、回帖之类针对一个内容进行回复的功能的时候,现在几乎全部都是采用ajax异步提交,并且同步在正确的位置显示提交结果,而不是在提交之后重新刷新整个页面来显示提交之后的内容。
ajax由于google的使用,被广为推广。它在客户端使用javascript语言编写,使用XMLHttpRequest对象,实现和服务的数据交互,详细信息参看:AJAX - XMLHttpRequest 对象。
ajax提交或者获取数据,常用数据形式包括:
ajax有几个好处:
也有一些缺点:
今天的例子是博客评论的异步提交,环境是python2.7+django1.2+SAE。
下面是后台的处理代码,view中的代码
- @csrf_exempt
- def comment_new(request,blog_id):
- blog=get_object_or_404(Blog,pk=blog_id)
- #str(request.raw_post_data)
- if request.method=="POST" and request.is_ajax():
- title=request.POST['comment_title']
- name=request.POST['comment_author_name']
- email=request.POST['comment_author_email']
- url=request.POST['comment_author_url']
- content=request.POST['comment_content']
- comment=Comment(title=title,author_name=name,author_email=email,author_url=url,content=content);
- comment.blog=blog
- comment=comment.save()
- _dict={}
- _dict["title"]=title
- _dict["author_name"]=name
- _dict["author_email"]=email
- _dict["author_url"]=url
- _dict["content"]=content
- _dict["created_at"]=unicode(datetime.datetime.now())
- return HttpResponse(simplejson.JSONEncoder().encode(str(_dict)))
- def obj2dict(obj):
- """
- summary:
- 将object转换成dict类型
- """
- memberlist = [m for m in dir(obj)]
- _dict = {}
- for m in memberlist:
- if m[0] != "_" and not callable(m):
- _dict[m] = getattr(obj,m)
- return _dict
下面是前段页面的代码
- <script type="text/javascript" src="/site_static/js/tiny_mce_jquery/tiny_mce.js"></script>
- <script type="text/javascript" src="/site_static/js/textareas_simple.js"></script>
- {% if comments %}
- <p>
- <h2>Comments:</h2>
- <div id="blog_comments">
- {% for comment in comments %}
- <p>
- <a href="{{ comment.author_url }}">{{ comment.author_name }}</a> Said at {{ comment.created_at }}
- </p>
- <p>
- <h3>Title:</h3>
- {{ comment.title }}
- </p>
- <p>
- <h3>Content:</h3>
- {% autoescape off %}
- {{ comment.content }}
- {% endautoescape %}
- </p>
- <hr>
- {% endfor %}
- </div>
- </p>
- {% else %}
- <h2>you are the first comment man, please!</h2>
- {% endif %}
- <p>
- <h2>New Comment:</h2>
- <script type="text/javascript">
- $(document).ready(function(){
- $("#comment_form").submit(function(e){
- var data=$('#comment_form').serialize();
- $.ajax({
- url:"/blog/{{ blog.id }}/comment/new/",
- type:"POST",
- contentType:"application/json; charset=utf-8",
- dataType:"json",
- data:data,
- success:function(data, textStatus, jqXHR){
- //alert(typeof(data));
- datadata=data.replace(/'/gi,"\"");
- datadata=data.replace(/u"/gi,"\"");
- //alert(data);
- var obj=$.parseJSON(data);
- //alert(obj.content);
- $("#blog_comments").append("<p><a href=\""+obj.author_url+"\">"+obj.author_name+"</a> Said at "+obj.created_at+"</p><p>"+obj.title+"</p><p>"+obj.content+"</p><hr>");
- $("#comment_form")[0].reset();
- },
- error:function(jqXHR, textStatus, errorThrown){
- alert(textStatus);
- alert(errorThrown);
- }
- });
- return false;
- });
- });
- </script>
- <form method="post" action="" id="comment_form">
- {% csrf_token %}
- {% comment %}
- {% for field in comment_form %}
- <p>
- {{ field.errors }}
- {{ field.label_tag }}:{{ field }}
- </p>
- {% endfor %}
- {% endcomment %}
- <p>
- <label for="comment_title">{{ comment_form.title.label }}</label>:
- <input type="text" id="comment_title" name="comment_title" placeholder="Title"/>
- {{ comment_form.title.help_text }}
- </p>
- <p>
- <label for="comment_author_name">{{ comment_form.author_name.label }}</label>:
- <input type="text" id="comment_author_name" name="comment_author_name" placeholder="author name"/>
- {{ comment_form.author_name.help_text }}
- </p>
- <p>
- <label for="comment_author_email">{{ comment_form.author_email.label }}</label>:
- <input type="text" id="comment_author_email" name="comment_author_email" placeholder="author email"/>
- {{ comment_form.author_email.help_text }}
- </p>
- <p>
- <label for="comment_author_url">{{ comment_form.author_url.label }}</label>:
- <input type="text" id="comment_author_url" name="comment_author_url" placeholder="author url"/>
- {{ comment_form.author_url.help_text }}
- </p>
- <p>
- <label for="comment_content">{{ comment_form.content.label }}</label>:
- <textarea rows="10" cols="50" placeholder="content" id="comment_content" name="comment_content"></textarea>
- {{ comment_form.content.help_text }}
- </p>
- <input type="submit" value="Save" />
- </form>
- </p>
在客户端用到了三个类库,分别是jquery-1.7.1.min.js,jquery.json-2.3.min.js和jquery.placeholder.min.js。
jquery是一个javascript类库,封装了javascript的很多操作,使用方便。
jquery.json是jquery的一个扩展,用来处理json文本和object之间的转换。
jquery.placeholder是jquery的一个扩展,用来实现在输入框没有内容的时候,添加一些提示信息。在输入框没有内容的时候,显示一些内容,提示你应该输入什么,输入的格式是什么。【placeholder是html5支持的一个属性,专门用来做提示的。】
- datadata=data.replace(/'/gi,"\"");
- datadata=data.replace(/u"/gi,"\"");
前段页面的上面这两句需要大家注意,第一句用正则表达式替换【单引号】为【双引号】,第二句替换【u+双引号】为【双引号】。这都是为了后面使用
$.parseJSON(data);
做准备的。因为python后台返回的json字符串,也就是data的值是下面的格式
- {'title':u'blog1','author':u'andyshi'}
字符串中有单引号和u,这都需要替换,jquery解析的json必须是标准格式的,就是双引号,而且不能包含其他内容,所以我进行了替换,然后才可以使用jquery.json进行解析。
u是因为python后台返回的是unicode字符串的缘故。应该有办法解决,待我再研究一下,稍后补充上来。
之前ajax返回的数据还需要处理单引号和字母u的问题,现在修正一下。
首先将前端的ajax代码变更为
- $.ajax({
- url:"/blog/{{ blog.id }}/comment/new/",
- type:"POST",
- contentType:"application/json; charset=utf-8",
- data:data,
- success:function(data, textStatus, jqXHR){
- var obj=$.parseJSON(data);
- $("#blog_comments").append("<p><a href=\""+obj.author_url+"\">"+obj.author_name+"</a> Said at "+obj.created_at+"</p><p>"+obj.title+"</p><p>"+obj.content+"</p><hr>");
- $("#comment_form")[0].reset();
- },
- error:function(jqXHR, textStatus, errorThrown){
- alert(textStatus);
- alert(errorThrown);
- }
- });
很明显,就是去掉了ajax参数dataType,返回的结果变成在服务端组织好的json字符串,然后用jquery.json解析成对象。顺便里面的两次替换就可以去掉了。
python后台的view代码变更为
- @csrf_exempt
- #@csrf_protect
- def comment_new(request,blog_id):
- blog=get_object_or_404(Blog,pk=blog_id)
- #str(request.raw_post_data)
- if request.method=="POST" and request.is_ajax():
- title=request.POST['comment_title']
- name=request.POST['comment_author_name']
- email=request.POST['comment_author_email']
- url=request.POST['comment_author_url']
- content=request.POST['comment_content']
- comment=Comment(title=title,author_name=name,author_email=email,author_url=url,content=content);
- comment.blog=blog
- comment=comment.save()
- #return string
- return HttpResponse("{\"title\":\"%s\",\"author_name\":\"%s\",\"author_email\":\"%s\",\"author_url\":\"%s\",\"content\":\"%s\",\"created_at\":\"%s\"}"
- % (title,name,email,url,content,unicode(datetime.datetime.now())))
直接返回我们自己构造的字符串,构造的时候就使用双引号拼接。这样就给前台省去了正则替换的操作。