1. 1.获取图片验证码:
  2. def get_validCode_img(request):
  3.  
  4. # 方式1:
  5. # import os
  6. # path= os.path.join(settings.BASE_DIR,"blog","static","img","egon.jpg")
  7. #
  8. # with open(path,"rb") as f:
  9. # data=f.read()
  10.  
  11. # 方式2:
  12. # from PIL import Image
  13. #
  14. # img=Image.new(mode="RGB",size=(120,40),color="green")
  15. #
  16. # f=open("validCode.png","wb")
  17. # img.save(f,"png")
  18. #
  19. # with open("validCode.png","rb") as f:
  20. # data=f.read()
  21.  
  22. # 方式3:
  23. # from io import BytesIO
  24. #
  25. # from PIL import Image
  26. # img = Image.new(mode="RGB", size=(120, 40), color="blue")
  27. # f=BytesIO()
  28. # img.save(f,"png")
  29. # data=f.getvalue()
  30. # return HttpResponse(data)
  31.  
  32. # 方式4 :
  33.  
  34. from io import BytesIO
  35. import random
  36.  
  37. from PIL import Image,ImageDraw,ImageFont
  38. img = Image.new(mode="RGB", size=(120, 40), color=(random.randint(0,255),random.randint(0,255),random.randint(0,255)))
  39.  
  40. draw=ImageDraw.Draw(img,"RGB")
  41. font=ImageFont.truetype("blog/static/font/kumo.ttf",25)
  42.  
  43. valid_list=[]
  44. for i in range(5):
  45.  
  46. random_num=str(random.randint(0,9))
  47. random_lower_zimu=chr(random.randint(65,90))
  48. random_upper_zimu=chr(random.randint(97,122))
  49.  
  50. random_char=random.choice([random_num,random_lower_zimu,random_upper_zimu])
  51. draw.text([5+i*24,10],random_char,(random.randint(0,255),random.randint(0,255),random.randint(0,255)),font=font)
  52. valid_list.append(random_char)
  53.  
  54. f=BytesIO()
  55. img.save(f,"png")
  56. data=f.getvalue()
  57.  
  58. valid_str="".join(valid_list)
  59. # print(valid_str)
  60.  
  61. request.session["keepValidCode"]=valid_str
  62.  
  63. return HttpResponse(data)
  64.  
  65. 2.点击验证码图片刷新效果
  66. $('.validCode_img').click(function () {
  67. console.log(this)
  68. this.src+="?"
  69. })
  70.  
  71. 3.注册form组件注意事项
  72. if form.is_valid():
  73.  
  74. username=form.cleaned_data['username'] #如果form过滤验证成功了 就直接在form.cleaned_data内取值就行,不必从request.POST中取值
  75. password=form.cleaned_data['password']
  76. email=form.cleaned_data['email']
  77. tel=form.cleaned_data['tel']
  78. avatar = request.FILES.get("avatar")
  79. if not avatar:
  80. #用户注册时未选取头像,那么在创建新用户时不用创建头像字段,因为在models中已经设置了默认值,不然在数据库中存的会是空
  81. models.UserInfo.objects.create_user(username=username,password=password,email=email,telephone=tel)
  82. else:
  83. models.UserInfo.objects.create_user(username=username,password=password,email=email,telephone=tel,avatar=avatar)
  84. form组件的局部钩子返回值 return self.cleaned_data['xxx']
  85. 全局猴子返回值 return self.cleaned_data
  86. #钩子函数中在 clean_data 取值时, 要用 get方法
  87.  
  88. 4.头像预览
  89.  
  90. <div class="form-group" id="i2">
  91.  
  92. {# 注意下面imginput 标签的前后顺序,如颠倒会出现点击图片不出现选择图片窗口 #}
  93. <label for="avatar">头像</label>
  94. <img src="/static/img/default.png/" alt="" class="c1" id="i1">
  95. <input type="file" id="avatar" class="c1">
  96. </div>
  97.  
  98. $("#avatar").change(function () {
  99.  
  100. var ele_file=$(this)[0].files[0]; //$(this)[0]和this 一样
  101. var reader=new FileReader();
  102. reader.readAsDataURL(ele_file);
  103. reader.onload=function () {
  104. $("#i1")[0].src=this.result
  105. }
  106. });
  107.  
  108. 5.注册时返回的错误信息的处理
  109. var errors_msg=data1['errors_msg'];
  110. $.each(errors_msg,function (i,v) {
  111. {# console.log(i,v);#}
  112. var ele=$('<span>');
  113. ele.html(v[0]).addClass('pull-right').css('color','red');
  114. $('#'+i).after(ele).parent().addClass('has-error')
  115. if(i=='__all__'){
  116.  
  117. $('#repassword').after(ele).parent().addClass('has-error')
  118. }
  119. })
  120.  
  121. 6.ajax在提交二进制数据时用formData
  122. var formData=new FormData();
  123. formData.append('username',$('#username').val());
  124. formData.append('avatar',$('#avatar')[0].files[0]);
  125.  
  126. $.ajax({
  127. url:'/reg/',
  128. type:'POST',
  129. data:formData,
  130. contentType:false,
  131. processData:false,
  132. headers:{"X-CSRFToken":$.cookie('csrftoken')}, #需要引用 <script src="/static/js/jquery.cookie.js"></script>
  133. #有时引用的cookie.js文件没有效果,那就换成 cdn 引用
  134.  
  135. 7.url路由分发与url反向解析
  136.  
  137. 根路径配置: url(r'^$', views.index), urlip+端口时,没有路径,执行index视图函数
  138.  
  139. 路由分发:
  140. '''
  141. Including another URLconf
  142. 1. Import the include() function: from django.conf.urls import url, include
  143. 2. Add a URL to urlpatterns: url()
  144. '''
  145. from django.conf.urls import url, include
  146.  
  147. url(r'^blog/',include('blog.urls')),
  148.  
  149. 反向解析:
  150.  
  151. url(r'^(?P<user>.*)/$',views.person_site,name='aaa'),
  152.  
  153. <a href="{% url 'aaa' request.user.username %}"></a> #注意 在url反向解析时,如需要参数就必须传
  154.  
  155. 8.首页的左侧菜单:
  156. index.html
  157. {% for site_category in site_category_list %}
  158. <div class="panel panel-success">
  159. <div class="panel-heading site_category">{{ site_category.name }}</div>
  160. <div class="panel-body hides">
  161. {% for obj in site_category.sitearticlecategory_set.all %}
  162. <a href="/cate/{{ obj.name }}/" style="text-decoration: none"><p>{{ obj.name }}</p></a> #在点击相应的分类是显示此分类的所有文章
  163. {% endfor %}
  164. </div>
  165. </div>
  166. {% endfor %}
  167.  
  168. urls.py
  169. url(r'^cate/(.*)/$', views.index),
  170.  
  171. views.py
  172. def index(request,*args):
  173.  
  174. if args:
  175. article_list = models.Article.objects.filter(site_article_category__name=args[0])
  176. else:
  177. article_list=models.Article.objects.all()
  178.  
  179. site_category_list=models.SiteCategory.objects.all()
  180.  
  181. return render(request,"index.html",{'article_list':article_list,'site_category_list':site_category_list})
  182.  
  183. css/js样式:
  184. <script>
  185. $('.site_category').mouseover(function () {
  186. console.log($(this))
  187. console.log(this) //打印两者的区别???
  188. $(this).next().slideDown(300)
  189. }).parent().mouseleave(function () {
  190. $(this).children('.panel-body').slideUp(300)
  191. })
  192. </script>
  193.  
  194. 9.头像图片在页面中显示的两种方式:
  195. <img src="/media/{{ user.user.avatar }}" width="60px" height="60px">
  196.  
  197. <img src="{{ user.user.avatar.url }}" width="60px" height="60px">
  198.  
  199. 10. media配置:
  200. settings.py
  201. MEDIA_ROOT=os.path.join(BASE_DIR,"blog","media","uploads")
  202. MEDIA_URL="/media/"
  203.  
  204. urls.py
  205. url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
  206.  
  207. 用处:
  208. ----- avatar = models.FileField(verbose_name='头像', upload_to='avatar', default="/avatar/default.png")
  209. 会把接收的文件放在media指代的路径与upload_to的拼接:
  210. BASE_DIR/blog/media/uploads/avatar/ xxx图片
  211.  
  212. avatar字段在数据库保存的是:avatar/a.png
  213.  
  214. ------
  215. 在页面中显示 <img src="/media/avatar/a.png">
  216.  
  217. 11. auth模块: http://www.cnblogs.com/liuwei0824/p/7772525.html
  218.  
  219. 12. 个人首页:
  220. 时间归档:
  221. date_list=models.Article.objects.filter(user=user_obj).extra(select={"filter_create_date":"strftime('%%Y/%%m',create_time)"}).values_list( "filter_create_date").annotate(Count("nid"))
  222.  
  223. 园龄:自定义过滤器用当前的时间对象-创建的时间对象
  224. 注意:在引用自定义过滤器时 要在body标签下 其他位置浏览器会出现小错误
  225.  
  226. 标签与分类归档有两种方式处理:
  227. 1. 在后端用分组聚合函数处理完成传入前端直接渲染
  228. 2. 在后端把文章对象传给前端,在前端深度查询进行渲染
  229.  
  230. 13. 评论树:
  231. views.py
  232. def commentTree(request,article_id):
  233. time_dict={}
  234. avatar_dict={}
  235. comment_all=models.Comment.objects.filter(article_id=article_id)
  236. for i in comment_all:
  237.  
  238. avatar='/media/'+str(i.user.avatar)
  239. time=str(i.create_time).split('.',1)[0][:-3]
  240. time_dict[i.nid]=time
  241. avatar_dict[i.nid]=avatar
  242.  
  243. comment_list=models.Comment.objects.filter(article_id=article_id).values('nid','user__username','user__avatar','content','parent_comment_id')
  244.  
  245. for i in comment_list:
  246. if i['nid'] in time_dict:
  247. i['create_time']=time_dict[i['nid']]
  248. if i['nid'] in time_dict:
  249. i['create_user_avatar'] = avatar_dict[i['nid']]
  250. i['children_list'] = []
  251.  
  252. d = {}
  253. for i in comment_list:
  254. d[i['nid']] = i
  255.  
  256. for i in comment_list:
  257. if i['parent_comment_id'] in d:
  258. d[i['parent_comment_id']]['children_list'].append(i)
  259.  
  260. li = []
  261. for i, j in d.items():
  262. if not j['parent_comment_id']:
  263. li.append(j)
  264. # print(li,66666666666666)
  265. import json
  266. return HttpResponse(json.dumps(li))
  267.  
  268. .html
  269. <h5>已发表评论(评论树):</h5>
  270. <div class="comment_tree_list">
  271.  
  272. </div>
  273. $.ajax({
  274.  
  275. url:'/blog/commentTree/'+$.cookie('article_obj_nid'),
  276. type:'get',
  277. success:function (data) {
  278. var data=JSON.parse(data);
  279.  
  280. <script>
  281. {# console.log(data[1]);#}
  282. var s=showCommentTree(data);
  283. $(".comment_tree_list").append(s);
  284. }
  285. })
  286.  
  287. function showCommentTree(comment_list) { // comment_list: [{"content":"","children_list":[{}]},{"content":""},{"content":""},]
  288. var html="";
  289.  
  290. $.each(comment_list,function (i,comment_dict) {
  291. var nid=comment_dict['nid'];
  292. var val=comment_dict["content"];
  293. var avatar=comment_dict["create_user_avatar"];
  294. var create_time=comment_dict["create_time"];
  295. var comment_username=comment_dict["user__username"];
  296. var ssss='<div class="row comment_content_haed"><div><span> '+'<img src='+avatar+' alt="" height="25px" width="25px" style="margin-right: 5px"></span>&nbsp;&nbsp;<a href="" style="text-decoration: none" class="comment_color c1">'+comment_username+'</a><span style="margin-left: 10px">'+create_time+'</span><a title="发送站内短消息" class="sendMsg2This" href="">&nbsp;</a></div><div class="comment_content_body"><p style="margin-left: 18px">'+val+'</p></div><div class="tig_head" comment_pid='+nid+'><a class="pull-right comment_color tig reply" style="text-decoration: none">回复</a><a class="pull-right tig comment_color" style="text-decoration: none">支持({{ comment_obj.up_count }})</a></div></div><hr style="margin-right: 60px">'
  297. var commnent_str= '<div class="comment"><div class="content"><span>'+ssss+'</span></div>';
  298.  
  299. if(comment_dict["children_list"]){
  300. var s=showCommentTree(comment_dict["children_list"]); // [{},{}]
  301. commnent_str+=s
  302. }
  303.  
  304. commnent_str+="</div>";
  305. html+=commnent_str
  306. });
  307.  
  308. return html
  309. }
  310. </script>
  311.  
  312. 14. 编辑器的防止xss攻击:用form组件过滤出敏感的标签及属性
  313. forms.py 引用xss
  314. class ArticleForm(Form):
  315.  
  316. content=fields.CharField(required=True,error_messages={'required':'不能为空'},
  317. widget=widgets.Textarea(attrs={'id':'comment_content'}))
  318.  
  319. def clean_content(self):
  320. from blog.plugins import xss_plugin
  321.  
  322. html_str=self.cleaned_data.get("content")
  323. clean_content=xss_plugin.filter_xss(html_str)
  324. self.cleaned_data["content"]=clean_content
  325.  
  326. return self.cleaned_data.get("content")
  327.  
  328. def filter_xss(html_str):
  329. valid_tag_list = ["p", "div", "a", "img", "html", "body", "br", "strong", "b"]
  330.  
  331. valid_dict = {"p": ["id", "class"], "div": ["id", "class"]}
  332.  
  333. from bs4 import BeautifulSoup
  334.  
  335. soup = BeautifulSoup(html_str, "html.parser") # soup -----> document
  336.  
  337. ######### 改成dict
  338. for ele in soup.find_all():
  339. # 过滤非法标签
  340. if ele.name not in valid_dict:
  341. ele.decompose()
  342. # 过滤非法属性
  343.  
  344. else:
  345. attrs = ele.attrs # p {"id":12,"class":"d1","egon":"dog"}
  346. l = []
  347. for k in attrs:
  348. if k not in valid_dict[ele.name]:
  349. l.append(k)
  350.  
  351. for i in l:
  352. del attrs[i]
  353.  
  354. print(soup)
  355.  
  356. return soup.decode() #默认decode 格式就是utf-8
  357.  
  358. 15. 后台管理:增删改查....
  359.  
  360. 16. kindeditor 编辑器文本域获取焦点 ???

blog项目知识点梳理的更多相关文章

  1. Django blog项目知识点总结

    数据库操作部分 当我们在Django项目中的models.py下写好创建表的代码后.为了创建好这些数据库表,我们再一次请出我的工程管理助手 manage.py.激活虚拟环境,切换到 manage.py ...

  2. BBS+Blog项目流程及补充知识点

    项目流程: 1. 产品需求 (1)基于用户认证组件和Ajax实现登陆验证(图片验证码) (2)基于forms组件和Ajax实现注册功能 (3)设计系统首页(文章列表渲染) (4)设计个人站点页面 (5 ...

  3. Django学习笔记(19)——BBS+Blog项目开发(3)细节知识点补充

    本文将BBS+Blog项目开发中所需要的细节知识点进行补充,其中内容包括KindEditor编辑器的使用,BeautifulSoup 模块及其防XSS攻击,Django中admin管理工具的使用,me ...

  4. Memcache知识点梳理

    Memcache知识点梳理 Memcached概念:    Memcached是一个免费开源的,高性能的,具有分布式对象的缓存系统,它可以用来保存一些经常存取的对象或数据,保存的数据像一张巨大的HAS ...

  5. [独孤九剑]Oracle知识点梳理(十)%type与%rowtype及常用函数

    本系列链接导航: [独孤九剑]Oracle知识点梳理(一)表空间.用户 [独孤九剑]Oracle知识点梳理(二)数据库的连接 [独孤九剑]Oracle知识点梳理(三)导入.导出 [独孤九剑]Oracl ...

  6. BBS项目知识点汇总

    目录 bbs项目知识点汇总 一. JavaScript 1 替换头像 2 form表单拿数据 3 form组件error信息渲染 4 添加html代码 5 聚焦操作 二 . html在线编辑器 三 . ...

  7. 1+x 证书 Web 前端开发 MySQL 知识点梳理

    官方QQ群 1+x 证书 Web 前端开发 MySQL 知识点梳理 http://blog.zh66.club/index.php/archives/199/

  8. Django学习笔记(18)——BBS+Blog项目开发(2)主体思路及流程

    这篇博客主要完成一个BBS+Blog项目,那么主要是模仿博客园的博客思路,使用Django框架进行练习. 准备:项目需求分析 在做一个项目的时候,我们首先做的就是谈清楚项目需求,功能需求,然后才开始写 ...

  9. Django快速学习搭建blog项目

    新手学习Django,本文学习的文档是<Django Web开发指南>.好了我也是新手,没什么好说了,go!- 首先先确定环境,我是在linux(Ubuntu14.04 gnome)下. ...

随机推荐

  1. 检测浏览器(BOM)以及地址栏网址的API

    navigator.userAgent //检测浏览器的版本以及那个厂商的 (不怎么准,你比如360经常跟别人干架,所以别人检测到360浏览器就提示浏览器危险,所以360就自己修改了) //分解这个地 ...

  2. Math.random 随机数方法

    随机取数方法 Math.random() 表示0到1之间随机取一个数 <x< 小数 Math.random()* 表示0<x< parseInt(Math.random()*) ...

  3. Codeforces 855C. Helga Hufflepuff's Cup----树形DP

    z最近在学习树形DP...好难啊. 在cf上找到了一题c题当模版马克一下. 题目不贴了..>>http://codeforces.com/problemset/problem/855/C& ...

  4. 3、Python迭代器、列表解析及生成器(0530)

    1.动态语言 sys.getrefcount()    //查看对象的引用计数 增加对象的引用计数场景 对象创建时:以赋值的方式,创建变量名的同时就会创建变量 将对象添加进容器时:类似list.app ...

  5. 【Ruby】【YAML】

    require "YAML" var = YAML.load(File.open('b.yml')) #哈希puts var.class #Hashprint var ," ...

  6. _faction

    一.自定义阵营独立于联盟,部落,联盟和部落玩家可以加入同一阵营 二._function_menu表可以配置自定义阵营开启 二.配合_pvp表,可以实现区域的自定义阵营PVP 三.配合_req表fact ...

  7. 使用ajax判断登录用户名

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Register.aspx. ...

  8. Thread.Sleep(0)妙用

    Thread.Sleep(0)妙用 我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间.那么你有没有正确的理解这个函数的用法呢?思考下面这两个问题: 假设现在是 2008-4-7  ...

  9. PCA分析和因子分析

    #由此说明使用prcomp函数时,必须使用标准化过的原始数据.如果使用没有标准化的raw数据(不是相关系数矩阵或者协方差矩阵),必须将参数scale. = T <result>$sdev ...

  10. 写给前端的Python依赖管理指北

    概述 在Python的项目中,我们可以通过pip来安装依赖包,但是不像npm install,pip默认安装的依赖包会挂在全局上,不利于项目工程协作. 这时候需要一款类似npm的工具记录我们的项目依赖 ...