[pthon2.7+django1.2+sae]博客评论的异步提交

简介:

在开发博客系统或者是电商系统,总之,凡是带有回复、评论、回帖之类针对一个内容进行回复的功能的时候,现在几乎全部都是采用ajax异步提交,并且同步在正确的位置显示提交结果,而不是在提交之后重新刷新整个页面来显示提交之后的内容。

ajax由于google的使用,被广为推广。它在客户端使用javascript语言编写,使用XMLHttpRequest对象,实现和服务的数据交互,详细信息参看:AJAX - XMLHttpRequest 对象

ajax提交或者获取数据,常用数据形式包括:

  • 普通文本,自己定义规则,自己解析,无成熟类库,需要自己编写。
  • xml文本,使用xml解析器解析,有成熟类库。
  • json文本,流行的数据形式,以体积小、灵活而著称,有成熟类库。

ajax有几个好处:

  • 防止页面刷新,因为提交的只是一部分内容,页面大部分内容没有发生改变,如果还是刷新进而重新获取全部的话,对于服务器和客户端都是一种负担。而且页面刷新还会产生其他问题,诸如重复提交之类的。
  • 减轻服务器负担,可以为更多人提供服务。

也有一些缺点:

  • 给编程和调试带来一些小麻烦,不够使用习惯了,还是有一些方法和窍门的。
  • 由于是ajax,所以页面地址没有变化,所以如果想分享地址的话,难以实现。需要做额外的工作,例如把地址打印出来,让用户复制分享。
  • 用户不容易知道自己的提交正在进行,因为页面没有刷新,用户可能会重新点击提交按钮。这也可以解决,提交过程给出明显提示,然后灰掉提交按钮,或者做一些防止重复提交的工作。

 

今天的例子是博客评论的异步提交,环境是python2.7+django1.2+SAE。

下面是后台的处理代码,view中的代码

 

 
  1.                       
  2. @csrf_exempt                  
  3. def comment_new(request,blog_id): 
  4.     blog=get_object_or_404(Blog,pk=blog_id) 
  5.      
  6.     #str(request.raw_post_data) 
  7.     if request.method=="POST" and request.is_ajax(): 
  8.         title=request.POST['comment_title'
  9.         name=request.POST['comment_author_name'
  10.         email=request.POST['comment_author_email'
  11.         url=request.POST['comment_author_url'
  12.         content=request.POST['comment_content'
  13.         comment=Comment(title=title,author_name=name,author_email=email,author_url=url,content=content); 
  14.         comment.blog=blog 
  15.         comment=comment.save() 
  16.  
  17.         _dict={} 
  18.         _dict["title"]=title 
  19.         _dict["author_name"]=name 
  20.         _dict["author_email"]=email 
  21.         _dict["author_url"]=url 
  22.         _dict["content"]=content 
  23.           _dict["created_at"]=unicode(datetime.datetime.now()) 
  24.      
  25.      
  26.     return HttpResponse(simplejson.JSONEncoder().encode(str(_dict))) 
  27.  
  28.  
  29. def obj2dict(obj): 
  30.     """ 
  31.     summary: 
  32.         将object转换成dict类型     
  33.     """ 
  34.     memberlist = [m for m in dir(obj)] 
  35.     _dict = {} 
  36.     for m in memberlist: 
  37.         if m[0] != "_" and not callable(m): 
  38.             _dict[m] = getattr(obj,m) 
  39.  
  40.     return _dict 

 

下面是前段页面的代码

 

 
  1. <script type="text/javascript" src="/site_static/js/tiny_mce_jquery/tiny_mce.js"></script> 
  2. <script type="text/javascript" src="/site_static/js/textareas_simple.js"></script> 
  3.  
  4. {% if comments %} 
  5. <p> 
  6. <h2>Comments:</h2> 
  7. <div id="blog_comments"> 
  8. {% for comment in comments %} 
  9. <p> 
  10. <a href="{{ comment.author_url }}">{{ comment.author_name }}</a>&nbsp;&nbsp;Said at {{ comment.created_at }} 
  11. </p> 
  12. <p> 
  13. <h3>Title:</h3> 
  14. {{ comment.title }} 
  15. </p> 
  16. <p> 
  17.     <h3>Content:</h3> 
  18.     {% autoescape off %} 
  19.     {{ comment.content }} 
  20.     {% endautoescape %} 
  21.  
  22. </p> 
  23. <hr> 
  24. {% endfor %} 
  25.  
  26. </div> 
  27.  
  28. </p> 
  29. {% else %} 
  30. <h2>you are the first comment man, please!</h2> 
  31. {% endif %} 
  32. <p> 
  33. <h2>New Comment:</h2> 
  34. <script type="text/javascript"> 
  35.     $(document).ready(function(){ 
  36.         $("#comment_form").submit(function(e){ 
  37.                      
  38.             var data=$('#comment_form').serialize(); 
  39.              
  40.             $.ajax({ 
  41.                 url:"/blog/{{ blog.id }}/comment/new/", 
  42.                 type:"POST", 
  43.                 contentType:"application/json; charset=utf-8", 
  44.                 dataType:"json", 
  45.                 data:data, 
  46.                 success:function(data, textStatus, jqXHR){ 
  47.                     //alert(typeof(data)); 
  48.                     datadata=data.replace(/'/gi,"\""); 
  49.                     datadata=data.replace(/u"/gi,"\""); 
  50.                     //alert(data); 
  51.                     var obj=$.parseJSON(data); 
  52.                     //alert(obj.content); 
  53.                     $("#blog_comments").append("<p><a href=\""+obj.author_url+"\">"+obj.author_name+"</a>&nbsp;&nbsp;Said at "+obj.created_at+"</p><p>"+obj.title+"</p><p>"+obj.content+"</p><hr>"); 
  54.                      
  55.                     $("#comment_form")[0].reset(); 
  56.                 }, 
  57.                 error:function(jqXHR, textStatus, errorThrown){ 
  58.                     alert(textStatus); 
  59.                     alert(errorThrown); 
  60.                 } 
  61.             });      
  62.              
  63.             return false; 
  64.  
  65.         }); 
  66.     }); 
  67.      
  68. </script> 
  69. <form method="post" action="" id="comment_form"> 
  70.  
  71.     {% csrf_token %} 
  72.      
  73.     {% comment %} 
  74.     {% for field in comment_form %} 
  75.     <p> 
  76.         {{ field.errors }} 
  77.         {{ field.label_tag }}:{{ field }} 
  78.     </p> 
  79.     {% endfor %} 
  80.          
  81.     {% endcomment %} 
  82.  
  83.     <p> 
  84.     <label for="comment_title">{{ comment_form.title.label }}</label>
  85.     <input type="text" id="comment_title" name="comment_title"  placeholder="Title"/> 
  86.     {{ comment_form.title.help_text }} 
  87.     </p> 
  88.      
  89.     <p> 
  90.     <label for="comment_author_name">{{ comment_form.author_name.label }}</label>
  91.     <input type="text" id="comment_author_name" name="comment_author_name" placeholder="author name"/> 
  92.     {{ comment_form.author_name.help_text }} 
  93.     </p> 
  94.      
  95.     <p> 
  96.     <label for="comment_author_email">{{ comment_form.author_email.label }}</label>
  97.     <input type="text" id="comment_author_email" name="comment_author_email"  placeholder="author email"/> 
  98.     {{ comment_form.author_email.help_text }} 
  99.     </p> 
  100.      
  101.     <p> 
  102.     <label for="comment_author_url">{{ comment_form.author_url.label }}</label>
  103.     <input type="text" id="comment_author_url" name="comment_author_url"  placeholder="author url"/> 
  104.     {{ comment_form.author_url.help_text }} 
  105.     </p> 
  106.      
  107.     <p> 
  108.     <label for="comment_content">{{ comment_form.content.label }}</label>
  109.     <textarea rows="10" cols="50" placeholder="content" id="comment_content" name="comment_content"></textarea> 
  110.      
  111.     {{ comment_form.content.help_text }} 
  112.     </p> 
  113.      
  114.  
  115.  
  116.  
  117.      
  118.      
  119.     <input type="submit" value="Save" /> 
  120. </form> 
  121.  
  122. </p> 

在客户端用到了三个类库,分别是jquery-1.7.1.min.jsjquery.json-2.3.min.jsjquery.placeholder.min.js

jquery是一个javascript类库,封装了javascript的很多操作,使用方便。

jquery.json是jquery的一个扩展,用来处理json文本和object之间的转换。

jquery.placeholder是jquery的一个扩展,用来实现在输入框没有内容的时候,添加一些提示信息。在输入框没有内容的时候,显示一些内容,提示你应该输入什么,输入的格式是什么。【placeholder是html5支持的一个属性,专门用来做提示的。】

 

 
  1. datadata=data.replace(/'/gi,"\"");  
  2. datadata=data.replace(/u"/gi,"\"");  

前段页面的上面这两句需要大家注意,第一句用正则表达式替换【单引号】为【双引号】,第二句替换【u+双引号】为【双引号】。这都是为了后面使用

$.parseJSON(data); 

做准备的。因为python后台返回的json字符串,也就是data的值是下面的格式

 

 
  1. {'title':u'blog1','author':u'andyshi'

字符串中有单引号和u,这都需要替换,jquery解析的json必须是标准格式的,就是双引号,而且不能包含其他内容,所以我进行了替换,然后才可以使用jquery.json进行解析。

u是因为python后台返回的是unicode字符串的缘故。应该有办法解决,待我再研究一下,稍后补充上来。

 

补充:

之前ajax返回的数据还需要处理单引号和字母u的问题,现在修正一下。

首先将前端的ajax代码变更为

 

 
  1. $.ajax({ 
  2.                 url:"/blog/{{ blog.id }}/comment/new/"
  3.                 type:"POST"
  4.                 contentType:"application/json; charset=utf-8"
  5.                  
  6.                 data:data, 
  7.                 success:function(data, textStatus, jqXHR){ 
  8.  
  9.                     var obj=$.parseJSON(data); 
  10.                      
  11.                     $("#blog_comments").append("<p><a href=\""+obj.author_url+"\">"+obj.author_name+"</a>&nbsp;&nbsp;Said at "+obj.created_at+"</p><p>"+obj.title+"</p><p>"+obj.content+"</p><hr>"); 
  12.                     $("#comment_form")[0].reset(); 
  13.                 }, 
  14.                 error:function(jqXHR, textStatus, errorThrown){ 
  15.                     alert(textStatus); 
  16.                     alert(errorThrown); 
  17.                 } 
  18.             });  

很明显,就是去掉了ajax参数dataType,返回的结果变成在服务端组织好的json字符串,然后用jquery.json解析成对象。顺便里面的两次替换就可以去掉了。

python后台的view代码变更为

 

 
  1. @csrf_exempt                  
  2. #@csrf_protect 
  3. def comment_new(request,blog_id): 
  4.     blog=get_object_or_404(Blog,pk=blog_id) 
  5.      
  6.     #str(request.raw_post_data) 
  7.     if request.method=="POST" and request.is_ajax(): 
  8.         title=request.POST['comment_title'
  9.         name=request.POST['comment_author_name'
  10.         email=request.POST['comment_author_email'
  11.         url=request.POST['comment_author_url'
  12.         content=request.POST['comment_content'
  13.         comment=Comment(title=title,author_name=name,author_email=email,author_url=url,content=content); 
  14.         comment.blog=blog 
  15.         comment=comment.save() 
  16.          
  17.     #return string 
  18.     return HttpResponse("{\"title\":\"%s\",\"author_name\":\"%s\",\"author_email\":\"%s\",\"author_url\":\"%s\",\"content\":\"%s\",\"created_at\":\"%s\"}"  
  19.         % (title,name,email,url,content,unicode(datetime.datetime.now()))) 

直接返回我们自己构造的字符串,构造的时候就使用双引号拼接。这样就给前台省去了正则替换的操作。

 




本文转自 virusswb 51CTO博客,原文链接:http://blog.51cto.com/virusswb/802039,如需转载请自行联系原作者

相关实践学习
基于小程序Serverless开发个人相册小程序
本场景基于小程序云Serverless+小程序开发者工具(IDE),快速搭建个人相册小程序
SAE的功能与使用入门
欢迎来到《SAE的功能与使用入门》,本课程是“云原生Serverless Clouder认证“系列中的第三阶段。课程将向您介绍阿里云Serverless应用引擎(SAE)服务相关的概念、特性与使用方式。通过课程将带您逐步深入探索Serverless世界,借助SAE服务,即使没有丰富的云计算和IT经验,也能够让开发人员在实际业务场景中便捷的掌握如何构建和部署应用程序,快速拥抱Serverless架构,将精力聚焦在应用代码和业务逻辑的实现上。 学习完本课程后,您将能够: 掌握Serverless应用引擎(SAE)的基本概念与核心优势 了解Serverless应用引擎(SAE)的核心功能 掌握使用Serverless应用引擎(SAE)的开发和部署流程 了解Serverless应用引擎(SAE)的适用场景和最佳实践 &nbsp;
目录
相关文章
|
1月前
|
缓存 中间件 API
使用 Django 的异步特性提升 I/O 类操作的性能
使用 Django 的异步特性提升 I/O 类操作的性能
41 0
|
6月前
|
JavaScript 前端开发 关系型数据库
Django+Vue快速实现博客网站
Django是一个开放源代码的Web应用框架,由Python写成。采用了MTV的框架模式,即模型M,视图V和模版T。它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是CMS(内容管理系统)软件。对于博客网站来说是典型的CMS应用。本文介绍通过Django+Vue的博客模版快速实现一个可用的博客网站。
186 1
|
10月前
|
消息中间件 缓存 NoSQL
Django开发-优化数据库实战解决方案(异步高效处理)
Django开发-优化数据库实战解决方案(异步高效处理)
141 0
|
敏捷开发 消息中间件 开发框架
一代版本一代神:利用Docker在Win10系统极速体验Django3.1真实异步(Async)任务
Django官方发布3.0版本,内核升级宣布支持Asgi,这一重磅消息让无数后台研发人员欢呼雀跃,弹冠相庆。大喜过望之下,小伙伴们兴奋的开箱试用,结果却让人大跌眼镜:非但说好的内部集成Websocket没有出现,就连原生的异步通信功能也只是个壳子,内部并未实现,很明显的换汤不换药,这让不少人转身投入了[FastAPI](https://v3u.cn/a_id_167)的怀抱。不过一年之后,今天8月,Django3.1版本姗姗来迟,这个新版本终于一代封神,不仅支持原生的异步视图,同时也支持异步中间件,明显整了个大活。
一代版本一代神:利用Docker在Win10系统极速体验Django3.1真实异步(Async)任务
|
存储 前端开发 JavaScript
使用python3.7+Vue.js2.0+Django2.0.4异步前端通过api上传文件到七牛云云端存储
之前一篇文章是通过普通js+tornado来上传七牛云:[使用Tornado配合七牛云存储api来异步切分上传文件](https://v3u.cn/a_id_123),本次使用vue+django来进行异步上传,因为毕竟vue.js才是目前的前端的主流。
使用python3.7+Vue.js2.0+Django2.0.4异步前端通过api上传文件到七牛云云端存储
|
SQL 前端开发 JavaScript
Django Blog | 09 这么简单!实现博客markdown输入和显示
Django Blog | 09 这么简单!实现博客markdown输入和显示
461 0
Django Blog | 09 这么简单!实现博客markdown输入和显示
|
API 数据库 数据安全/隐私保护
Django API 开发:博客系统的权限管理(下)
安全性是任何网站的重要组成部分,但对于 Web API 而言则至关重要。 目前,我们的 Blog API 允许任何人进行完全访问。 没有任何限制; 任何用户都可以做任何极其危险的事情。 例如,匿名用户可以创建,阅读,更新或删除任何博客文章。 他们甚至没有创造一个! 显然,我们不希望这样做。
|
安全 API 数据安全/隐私保护
Django API 开发:博客系统的权限管理(中)
安全性是任何网站的重要组成部分,但对于 Web API 而言则至关重要。 目前,我们的 Blog API 允许任何人进行完全访问。 没有任何限制; 任何用户都可以做任何极其危险的事情。 例如,匿名用户可以创建,阅读,更新或删除任何博客文章。 他们甚至没有创造一个! 显然,我们不希望这样做。
|
API 数据安全/隐私保护 网络架构
Django API 开发:博客系统的权限管理(上)
安全性是任何网站的重要组成部分,但对于 Web API 而言则至关重要。 目前,我们的 Blog API 允许任何人进行完全访问。 没有任何限制; 任何用户都可以做任何极其危险的事情。 例如,匿名用户可以创建,阅读,更新或删除任何博客文章。 他们甚至没有创造一个! 显然,我们不希望这样做。
|
JSON API 网络架构
Django API 开发:博客系统接入 API(下)
我们的下一个项目是使用 Django REST Framework 功能的博客 API。 它将具有用户,权限,并允许完整的 CRUD(创建-读取-更新-删除)功能。 我们还将探索视图集,路由器和文档。 在本文中,我们将构建博客系统基本的 API 部分。