1.获取图片验证码:
def get_validCode_img(request): # 方式1:
# import os
# path= os.path.join(settings.BASE_DIR,"blog","static","img","egon.jpg")
#
# with open(path,"rb") as f:
# data=f.read() # 方式2:
# from PIL import Image
#
# img=Image.new(mode="RGB",size=(120,40),color="green")
#
# f=open("validCode.png","wb")
# img.save(f,"png")
#
# with open("validCode.png","rb") as f:
# data=f.read() # 方式3:
# from io import BytesIO
#
# from PIL import Image
# img = Image.new(mode="RGB", size=(120, 40), color="blue")
# f=BytesIO()
# img.save(f,"png")
# data=f.getvalue()
# return HttpResponse(data) # 方式4 : from io import BytesIO
import random from PIL import Image,ImageDraw,ImageFont
img = Image.new(mode="RGB", size=(120, 40), color=(random.randint(0,255),random.randint(0,255),random.randint(0,255))) draw=ImageDraw.Draw(img,"RGB")
font=ImageFont.truetype("blog/static/font/kumo.ttf",25) valid_list=[]
for i in range(5): random_num=str(random.randint(0,9))
random_lower_zimu=chr(random.randint(65,90))
random_upper_zimu=chr(random.randint(97,122)) random_char=random.choice([random_num,random_lower_zimu,random_upper_zimu])
draw.text([5+i*24,10],random_char,(random.randint(0,255),random.randint(0,255),random.randint(0,255)),font=font)
valid_list.append(random_char) f=BytesIO()
img.save(f,"png")
data=f.getvalue() valid_str="".join(valid_list)
# print(valid_str) request.session["keepValidCode"]=valid_str return HttpResponse(data) 2.点击验证码图片刷新效果
$('.validCode_img').click(function () {
console.log(this)
this.src+="?"
}) 3.注册form组件注意事项
if form.is_valid(): username=form.cleaned_data['username'] #如果form过滤验证成功了 就直接在form.cleaned_data内取值就行,不必从request.POST中取值
password=form.cleaned_data['password']
email=form.cleaned_data['email']
tel=form.cleaned_data['tel']
avatar = request.FILES.get("avatar")
if not avatar:
#用户注册时未选取头像,那么在创建新用户时不用创建头像字段,因为在models中已经设置了默认值,不然在数据库中存的会是空
models.UserInfo.objects.create_user(username=username,password=password,email=email,telephone=tel)
else:
models.UserInfo.objects.create_user(username=username,password=password,email=email,telephone=tel,avatar=avatar)
form组件的局部钩子返回值 : return self.cleaned_data['xxx']
全局猴子返回值 : return self.cleaned_data
#钩子函数中在 clean_data 取值时, 要用 get方法 4.头像预览 <div class="form-group" id="i2"> {# 注意下面img与input 标签的前后顺序,如颠倒会出现点击图片不出现选择图片窗口 #}
<label for="avatar">头像</label>
<img src="/static/img/default.png/" alt="" class="c1" id="i1">
<input type="file" id="avatar" class="c1">
</div> $("#avatar").change(function () { var ele_file=$(this)[0].files[0]; //$(this)[0]和this 一样
var reader=new FileReader();
reader.readAsDataURL(ele_file);
reader.onload=function () {
$("#i1")[0].src=this.result
}
}); 5.注册时返回的错误信息的处理
var errors_msg=data1['errors_msg'];
$.each(errors_msg,function (i,v) {
{# console.log(i,v);#}
var ele=$('<span>');
ele.html(v[0]).addClass('pull-right').css('color','red');
$('#'+i).after(ele).parent().addClass('has-error')
if(i=='__all__'){ $('#repassword').after(ele).parent().addClass('has-error')
}
}) 6.ajax在提交二进制数据时用formData
var formData=new FormData();
formData.append('username',$('#username').val());
formData.append('avatar',$('#avatar')[0].files[0]); $.ajax({
url:'/reg/',
type:'POST',
data:formData,
contentType:false,
processData:false,
headers:{"X-CSRFToken":$.cookie('csrftoken')}, #需要引用 <script src="/static/js/jquery.cookie.js"></script>
#有时引用的cookie.js文件没有效果,那就换成 cdn 引用 7.url路由分发与url反向解析 根路径配置: url(r'^$', views.index), url是ip+端口时,没有路径,执行index视图函数 路由分发:
'''
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url()
'''
from django.conf.urls import url, include url(r'^blog/',include('blog.urls')), 反向解析: url(r'^(?P<user>.*)/$',views.person_site,name='aaa'), <a href="{% url 'aaa' request.user.username %}"></a> #注意 在url反向解析时,如需要参数就必须传 8.首页的左侧菜单:
index.html
{% for site_category in site_category_list %}
<div class="panel panel-success">
<div class="panel-heading site_category">{{ site_category.name }}</div>
<div class="panel-body hides">
{% for obj in site_category.sitearticlecategory_set.all %}
<a href="/cate/{{ obj.name }}/" style="text-decoration: none"><p>{{ obj.name }}</p></a> #在点击相应的分类是显示此分类的所有文章
{% endfor %}
</div>
</div>
{% endfor %} urls.py
url(r'^cate/(.*)/$', views.index), views.py
def index(request,*args): if args:
article_list = models.Article.objects.filter(site_article_category__name=args[0])
else:
article_list=models.Article.objects.all() site_category_list=models.SiteCategory.objects.all() return render(request,"index.html",{'article_list':article_list,'site_category_list':site_category_list}) css/js样式:
<script>
$('.site_category').mouseover(function () {
console.log($(this))
console.log(this) //打印两者的区别???
$(this).next().slideDown(300)
}).parent().mouseleave(function () {
$(this).children('.panel-body').slideUp(300)
})
</script> 9.头像图片在页面中显示的两种方式:
<img src="/media/{{ user.user.avatar }}" width="60px" height="60px"> <img src="{{ user.user.avatar.url }}" width="60px" height="60px"> 10. media配置:
settings.py
MEDIA_ROOT=os.path.join(BASE_DIR,"blog","media","uploads")
MEDIA_URL="/media/" urls.py
url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}), 用处:
----- avatar = models.FileField(verbose_name='头像', upload_to='avatar', default="/avatar/default.png")
会把接收的文件放在media指代的路径与upload_to的拼接:
BASE_DIR/blog/media/uploads/avatar/ xxx图片 avatar字段在数据库保存的是:avatar/a.png ------
在页面中显示 <img src="/media/avatar/a.png"> 11. auth模块: http://www.cnblogs.com/liuwei0824/p/7772525.html 12. 个人首页:
时间归档:
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")) 园龄:自定义过滤器用当前的时间对象-创建的时间对象
注意:在引用自定义过滤器时 要在body标签下 其他位置浏览器会出现小错误 标签与分类归档有两种方式处理:
1. 在后端用分组聚合函数处理完成传入前端直接渲染
2. 在后端把文章对象传给前端,在前端深度查询进行渲染 13. 评论树:
views.py
def commentTree(request,article_id):
time_dict={}
avatar_dict={}
comment_all=models.Comment.objects.filter(article_id=article_id)
for i in comment_all: avatar='/media/'+str(i.user.avatar)
time=str(i.create_time).split('.',1)[0][:-3]
time_dict[i.nid]=time
avatar_dict[i.nid]=avatar comment_list=models.Comment.objects.filter(article_id=article_id).values('nid','user__username','user__avatar','content','parent_comment_id') for i in comment_list:
if i['nid'] in time_dict:
i['create_time']=time_dict[i['nid']]
if i['nid'] in time_dict:
i['create_user_avatar'] = avatar_dict[i['nid']]
i['children_list'] = [] d = {}
for i in comment_list:
d[i['nid']] = i for i in comment_list:
if i['parent_comment_id'] in d:
d[i['parent_comment_id']]['children_list'].append(i) li = []
for i, j in d.items():
if not j['parent_comment_id']:
li.append(j)
# print(li,66666666666666)
import json
return HttpResponse(json.dumps(li)) .html
<h5>已发表评论(评论树):</h5>
<div class="comment_tree_list"> </div>
$.ajax({ url:'/blog/commentTree/'+$.cookie('article_obj_nid'),
type:'get',
success:function (data) {
var data=JSON.parse(data); <script>
{# console.log(data[1]);#}
var s=showCommentTree(data);
$(".comment_tree_list").append(s);
}
}) function showCommentTree(comment_list) { // comment_list: [{"content":"","children_list":[{}]},{"content":""},{"content":""},]
var html=""; $.each(comment_list,function (i,comment_dict) {
var nid=comment_dict['nid'];
var val=comment_dict["content"];
var avatar=comment_dict["create_user_avatar"];
var create_time=comment_dict["create_time"];
var comment_username=comment_dict["user__username"];
var ssss='<div class="row comment_content_haed"><div><span> '+'<img src='+avatar+' alt="" height="25px" width="25px" style="margin-right: 5px"></span> <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=""> </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">'
var commnent_str= '<div class="comment"><div class="content"><span>'+ssss+'</span></div>'; if(comment_dict["children_list"]){
var s=showCommentTree(comment_dict["children_list"]); // [{},{}]
commnent_str+=s
} commnent_str+="</div>";
html+=commnent_str
}); return html
}
</script> 14. 编辑器的防止xss攻击:用form组件过滤出敏感的标签及属性
forms.py 引用xss
class ArticleForm(Form): content=fields.CharField(required=True,error_messages={'required':'不能为空'},
widget=widgets.Textarea(attrs={'id':'comment_content'})) def clean_content(self):
from blog.plugins import xss_plugin html_str=self.cleaned_data.get("content")
clean_content=xss_plugin.filter_xss(html_str)
self.cleaned_data["content"]=clean_content return self.cleaned_data.get("content") def filter_xss(html_str):
valid_tag_list = ["p", "div", "a", "img", "html", "body", "br", "strong", "b"] valid_dict = {"p": ["id", "class"], "div": ["id", "class"]} from bs4 import BeautifulSoup soup = BeautifulSoup(html_str, "html.parser") # soup -----> document ######### 改成dict
for ele in soup.find_all():
# 过滤非法标签
if ele.name not in valid_dict:
ele.decompose()
# 过滤非法属性 else:
attrs = ele.attrs # p {"id":12,"class":"d1","egon":"dog"}
l = []
for k in attrs:
if k not in valid_dict[ele.name]:
l.append(k) for i in l:
del attrs[i] print(soup) return soup.decode() #默认decode 格式就是utf-8 15. 后台管理:增删改查.... 16. kindeditor 编辑器文本域获取焦点 ???