博客园项目
kindEditor文本编辑框的使用 图片在此的上传 >>点我
需要注意的点:
1.不能在函数内部引用数据用from my_stlye import * 这样会有问题出现
2

在用ajax来验证用户名密码是否正确,正确就转到响应页面的情况下
form表单中不能用
<input type="submit" id="ub" class="btn btn-primary pull-right" value="提交">
submit 按钮 默认有提交功能,所以不能用他 14:30
要用
<input type="button" id="ub" class="btn btn-primary pull-right" value="提交">




{# labe标签中的for='id_avatar' 对应着下边input的 id='id_avatar'#} {# 这样可以实现点击label 标签中的内容而触发input 标签被选中 #} <label for="id_avatar">{{ user_info.avatar.label }} <img id="avatar_img" height="70" width="70" src="/static/imgs/tou.jpg" alt=""> </label> {# 可以直接在这儿引入静态文件 图片是放到了static文件夹中, 隐藏 点击上边的label 中的内容触发这个标签中的事件#} <input type="file" style="display: none" id="id_avatar" >
动态显示刚刚上传的图片
$('#id_avatar').change(function () {
{# 获取用户上传的文件的信息,这里面包含 下面这些信息#}
{# File(21947) {name: "QQ截图20180202200130.png", #}
{# lastModified: 1517572893146, lastModifiedDate:#}
{# Fri Feb 02 2018 20:01:33 GMT+0800 (中国标准时间), webkitRelativePath: "", size: 21947, …}#}
var choose_file = $(this)[0].files[0];
{# 实例化一个阅读器对象 #}
var reader = new FileReader();
{# 调用阅读器对象的方法,将刚刚上穿的文件地址读出来 注意他没有返回值#}
reader.readAsDataURL(choose_file);
{# 阅读器在读这个地址的过程需要一段时间 可能没有读完,#}
{# 下边的内容就已经开始了#}
{# reader.onload这个是等他读完后才进行下边的过程#}
reader.onload = function () {
{# this 就是指绑定这个事件的 当前的reader对象#}
$('#avatar_img').attr('src',this.result);
{# 给图片位置附上一个新的地址的值 让新上传的图片地址替换默认图片的地址#}
{# 显示出当前的 图片地址 this.result 就相当于在执行 reader.result 取出 URL的值#}
}
});
需要上传文件,这里要设置 enctype='multipart/form-data'的这种格式

文件上传
基于form表单

HTML中的写法

view代码
def test(request): if request.method=='POST': # print(request.POST) print(request.FILES.get('f')) # 获取文件 f obj=request.FILES.get('f') obj_name=obj.name#拿到传过来的文件的名字 # 将文件以拿到的文件的名字为名字写入 print( '这是文件的名字>>>',obj_name) f_write=open(obj_name,'wb') for line in obj: f_write.write(line) return HttpResponse('ok') return render(request,'test.html')
html代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <form action="" method="post" enctype="multipart/form-data"> {% csrf_token %} <input type="file" name="f"> <input type="submit"> </form> </body> </html>
基于ajax
{# 点击提交按钮#} $('#ub').click(function () { {# 拼接数据, 先实例化一个FormData对象,通过append方法将键值对放到这里边,将formdata对象传到view视图中去 #} var formdata=new FormData(); {# 这些数据传过去会拼接成键值对的形式,放到这个formdata对象中去#} formdata.append('user',$('[name="user"]').val()); formdata.append('file', $('#id_avatar')[0].files[0]); formdata.append( 'csrfmiddlewaretoken',$('[name="csrfmiddlewaretoken"]').val()); $.ajax( { url:'/app01/register/', data:formdata, #将formdata传过去给view去 type:'post', {# 用ajax传数据(带文件的)过去 下边这两个参数一定要写#} contentType:false, processData:false, success:function (data) { console.log(data) } } ) })
view视图中接收的提交过来的数据和打印的的信息

注册之打印错误信息
1.each()方法打印之打印类表

效果

each()之打印字典中的内荣

效果


用each()循环在页面将错误信息打印出来

全局错误信息这样提取和显示

上传的头像存放的位置

当这个文件中没有设置upload_to 的地址时

设置之后传的效果

上传完后

3 media配置: 静态文件: static css js img font 用户上传文件 media avatar/ ...../ 针对FileField,Imagefield字段: 1 avatar = models.FileField(upload_to = 'avatars/',default="/avatar/default.png") 默认会将FileField字段中的upload_to参数对应的值avatars文件下载到项目的根目录下 如果没有配置会将上传的文件放到根目录下 if 在settings配置了一句: MEDIA_ROOT=os.path.join(BASE_DIR,"blog","media") 配置之后会将FileField字段中的upload_to参数对应的值avatar会放到下载MEDIA_ROOT路径下 ################################# 使用media settings.py: MEDIA_URL="/media/" (/media/ 实际就是指代的下边media_root的路径) 相当于加了一个路由 与上边的MEDIA_ROOT一同使用
MEDIA_ROOT=os.path.join(BASE_DIR,"blog","media")
这句话的作用是为了让在浏览器上可以加载到头像等用户上传的数据,(达到输入上传的文件路径127.0.0.1:8000/app01/media/avatars/touxiang.png 地址就可以取到数据)
类似于加载静态文件 (没有在urls文件夹中设置路由同样可以加载数据 详见上图) 也是在HTLM中放入头像路径就可以加载
能够根据地址去 路由 然后去到数据
urls.py:
from django.views.static import serve
from . import settings
url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
models里边配置的为文件类型 地址是avatars

但是 在setting中配置了MEDIA_ROOT之后 用于存放上传文件的文件夹会放到这里边


注册 带上传文件的
def register(request): if request.method=='POST': # print(request.POST) # print('这是file文件',request.FILES.get('file')) # 这里也要传 request.FILES 因为头像不在POST里边,不这样写的话 实例化的对象会缺少头像信息,所以会报错 user_info = User_info(request.POST,request.FILES) msg_data = {'user': None, 'error_msg': None}
#定义一个字典,传给 HTML 当验证通过时 user中的键是一个值,error_msg值是None反之 if user_info.is_valid(): user=request.POST.get('user') pwd=request.POST.get('pwd') nickname=request.POST.get('nickname') phone=request.POST.get('phone') avatar=request.FILES.get('avatar') use1=models.UserInfo.objects.create_user(username=user,password=pwd,nickname=nickname,telephone=phone,avatar=avatar) msg_data['user']=use1.username else: print('这是正常的效果',user_info.errors) # 这是正常的效果 <ul class="errorlist"><li>user<ul class="errorlist"><li>请输入用户名</li></ul></li><li>pwd<ul class="errorlist">
<li>请输入用密码</li></ul></li><li>pwd1<ul class="errorlist"><li>请确认密码</li></ul></li><li>nickname<ul class="errorlist"><li>请输入昵称</li>
</ul></li><li>phone<ul class="errorlist"><li>请输入用电话</li></ul></li></ul> print('这是强转字典的效果',dict(user_info.errors)) #这里要强转字典,将error中的信息取出 # {'user': ['请输入用户名'], 'pwd': ['请输入用密码'], 'pwd1': ['请确认密码'], 'nickname': ['请输入昵称'], 'phone': ['请输入用电话']} msg_data['error_msg'] = user_info.errors print(msg_data) return HttpResponse(json.dumps(msg_data)) user_info=User_info() return render(request, 'register.html', {'user_info':user_info})

分类列表查找

# 这样配置能够访问根地址来访问index页面
url(r'^$', views.index),
三 . 文章详情页之使用自定义标签来继承

用到了自定义标签的知识点
自己写自定义的标签

代码
from django import template from django.utils.safestring import mark_safe register=template.Library() from app01 import models from django.db.models import Max,Min,Count,Sum # 自定义标签 注册 @register.inclusion_tag('archive.html') # 此种类型的自定义标签可以先执行自定义的函数中的内容,在讲内容生成的数据写入渲染到html文件中,最后返回的是一个HTML文件 def get_archive_style(username): # 将文章的标签,分类,日期等分类的数据的函数放在这个中执行,得到数据 print('执行tag了') print(username) user = models.UserInfo.objects.filter(username=username).first() print(user.username) blog = user.blog print('得到blog了',blog) category_list = models.HomeCategory.objects.filter(blog=blog).annotate(c=Count('article__nid')).values_list('title', 'c') # tag 标签 和数量 这个与文章分类类似 只是他是多对多 查的方法是一样的 tag_list = models.Tag.objects.filter(blog=blog).annotate(c=Count('article__nid')).values_list('title', 'c') # 以时间来分组 date_list = models.Article.objects.filter(user=user) \ .extra(select={'create_data_ym': 'DATE_FORMAT(create_time,"%%Y-%%m")'}) \ .values('create_data_ym').annotate(c=Count('nid')).values_list('create_data_ym', 'c') # 返回得到的分类数据, 数据会返回给上边@register.inclusion_tag('archive.html') 内的html 文件中去渲染页面 return {'category_list':category_list,'tag_list':tag_list,'date_list':date_list,'blog':blog}

代码
{% extends 'temp.html' %} {#在这儿一定要写上这句话来加载自定义的templatetag文件#} {% load my_tags %} {% block page %} 你好》》{{ request.user }} <div> <span>{{ blog.title }}</span> {{ blog.site }} 这是{{ blog.theme }} </div> <div class="container"> <div class="row"> {# 左侧菜单#} <div class="col-md-3"> {# 执行函数,传入username数据 #} {% get_archive_style username %} {# 他会返回渲染好的HTML文件#} </div> {# 文章#} <div class="col-md-6"> {% for aticle in article_list %} <div class="media"> <div class="media-body " style="font-size: 12px" > <div class="media"> <h4 class="media-heading"><a href="">{{ aticle.title }}</a></h4> <div class="media-body " style="font-size: 12px" > {{ aticle.desc|truncatechars:50 }} </div> <div class="pull-right"> <span><a href="">{{ aticle.user.username }}
</a> 发布于 {{ aticle.create_time|date:'Y-m-d H:i:s' }}</span> </div> </div> </div> </div> <hr> {% endfor %} </div> {# 右侧对象#} <div class="col-md-3"></div> </div> </div> {% endblock %}
JS语言中if条件为false的情况
总结:
1、逻辑对象无初始值或者其值为 0、-0、null、""、false、undefined 或者 NaN,那么if判断 false ,其他为true
2、jq选择器选择返回的对象永远是jq的object对象
js语言的模版语言的用法
{# 在js的渲染中 模板语言要加引号,否则就不能正常找出数据#} if ("{{ request.user.username}}"){ $.ajax({ url: '/app01/upandown/', type: 'post', data: {'username':"{{request.user.username}}",'art_id':"{{ art.nid }}",
'csrfmiddlewaretoken': $('input[name="csrfmiddlewaretoken"]').val()}, success: function (data) { data=JSON.parse(data); if(data.state){ var a=parseInt($('#digg_count').html()+1); $('#digg_count').html(a); alert('ok')
四 点赞踩灭功能
html代码
{% extends 'temp.html' %} {% load my_tags %} {% block page %} 你好》》{{ request.user }} {% csrf_token %} <div> <span>{{ blog.title }}</span> {{ blog.site }} 这是{{ blog.theme }} </div> <div class="container"> <div class="row"> {# 左侧菜单#} <div class="col-md-3"> {# 执行函数,传入username数据 #} {% get_archive_style username %} {# 他会返回渲染好的HTML文件#} </div> {# 文章#} <div class="col-md-6"> <h3>{{ art.title }}</h3> <span>{{ art.articledetail.content|safe }}</span> </div> {# 右侧对象#} <div class="col-md-3"></div> </div> <div class="row"> <div id="div_digg"> <div class="digg diggit" > <span class="diggnum" id="digg_count">{{ art.up_count }}</span> </div> <div class="digg buryit" > <span class="burynum" id="bury_count">{{ art.down_count }}</span> </div> <div class="clear"></div> <div class="diggword" id="digg_tips" style="color: red;"></div> </div> </div> </div> {% endblock %} {% block js %} <script> {# 点赞踩灭功能#} $('.digg').click(function () { {# 这句话是判断是否含有diggit类 返回布尔值 如果返回的结果是 ture 即表示点的是点赞功能,否则是踩灭供嫩#} {# 这里需注意的是 js 语言中的布尔值是 小写的 ture false 所以数据传到python 中判断时要注意转换#} var is_up=$(this).hasClass('diggit'); console.log(is_up); {# 在js的渲染中 模板语言要加引号,否则就不能正常找出数据#} {# 当用户已经登录时 即使当下边的值不是空字符串时 #} if ("{{ request.user.username}}"){ $.ajax({ url: '/app01/upandown/', type: 'post', {# 将点赞的文章id 传过去,因为点赞人就是当前登录人,所有这里不用传 #} {# 在视图函数中可以直接取到user对象(django中间键中有user) 用request.user的方法取到登录的对象#} data: {'art_id':"{{ art.nid }}",'csrfmiddlewaretoken': $('input[name="csrfmiddlewaretoken"]').val(),'is_up':is_up}, success: function (data) {
传过来的data是一个字典,里边的的布尔值表示是否点赞踩灭成功 data=JSON.parse(data); {# 当没有报错时即当 data.state是ture时 走下边的代码#} if(data.state){ {# 当用户点的是点赞功能时,给点赞框中的数据加1#} if(is_up){ var a=parseInt($('#digg_count').html()+1); $('#digg_count').html(a); alert('ok') }else{ var a=parseInt($('#bury_count').html()+1); $('#bury_count').html(a); alert('ok')} {# 当有错误信息时 打印错误信息#} }else{ $('#digg_tips').html('你已经操作过了').attr('color', 'red') } } }); {# 当用户没有登录时 #} }else{ $('#digg_tips').html('请登录').attr('color', 'red') } }) </script> {% endblock %}
试图函数中的代码
# 点赞踩 from django.db.models import F # 引入模块用于事务 from django.db import transaction def upandown(request): userid=request.user.nid art_id=request.POST.get('art_id') is_up=request.POST.get('is_up') print(userid,art_id)
#创建一个字典,用于存放信号,当时True时表示点赞踩灭成功,当时False表示添加失败 response={'state':True} try: # 写上一句这个,将要执行的内容写在这里边就可以了,是对事物运用。 with transaction.atomic(): if is_up=='true':
#函数 一个是去点赞踩灭数据库中添加数据 new_zan=models.ArticleUpDown.objects.create(article_id=art_id,user_id=userid)
#这个函数是在文章数据库中给点赞踩灭添加数量 models.Article.objects.filter(nid=art_id).update(up_count=F('up_count')+1) print('添夹成果')
#否则是踩灭功能,更新数据 else: new_down = models.ArticleUpDown.objects.create(article_id=art_id, user_id=userid,is_up=False) models.Article.objects.filter(nid=art_id).update(down_count=F('down_count') + 1) print('添夹成果')
#当报错时,即当添加失败时(因为点赞踩灭功能中的 点赞者id和文章id是联合唯一 当不是时就是已经点赞踩灭过 就会报错) except Exception as e: response['state']=False print('添加失败')
#将字典传回去 data=json.dumps(response) return HttpResponse(data)
提交评论功能
js代码
{# 提交评论功能#} $('#btn_comment_submit').click(function () { {# 判断有没有登录#} var pinglunren="{{ request.user.username }}"; {# 如果登录了走这儿#} if(pinglunren){ {# 如果是回复其他楼层的评论 子评论(即parent_comment_pk不是空字符串),走这儿#} if(parent_comment_pk){ $.ajax({ url:'/app01/comment/', type:'post', {# 与直接写根评论的区别是这个传入的data中的parent_comment_pk的值是确定的值#} data:{'art_id':'{{ art.nid }}','username':'{{ art.user.username }}'
,'content':$('#tbCommentBody').val(),'parent_comment_pk':parent_comment_pk,'csrfmiddlewaretoken': $('input[name="csrfmiddlewaretoken"]').val()}, success:function (data) { data=JSON.parse(data); console.log(data.create_time);
#用Ajax实现局部刷新刚提交的评论的功能 var forloop_count=$(".feedbackItem").length+1; #得到当前的评论楼层数 $('#comment_date').html(data.create_time); $('#comment_anchor').html(data.user); $('#comment_body_').html(data.content);
#写好要渲染的内容 写成字符串的形式, 用append 的方法加入到HTML正文中去 var s='<div class="feedbackCon"><div id="comment_body_" class="blog_comment_body">'+data.content +'</div></div>'; $('.comment_lou').append(s) } {# 当不是回复其他楼层的评论时 根评论,走这儿#} })}else{ $.ajax({ url:'/app01/comment/', type:'post', {# 这里传入的的parent_comment_pk的值是空字符串, 将数据传到view函数 依照这个参数来判断评论时跟评还是子评论#} data:{'art_id':'{{ art.nid }}','username':'{{ art.user.username }}'
,'content':$('#tbCommentBody').val(),'parent_comment_pk':'','csrfmiddlewaretoken': $('input[name="csrfmiddlewaretoken"]').val()}, success:function (data) { data=JSON.parse(data); console.log(data.create_time); var forloop_count=$(".feedbackItem").length+1; console.log('这是楼数',forloop_count); $('#comment_date').html(data.create_time); $('#comment_anchor').html(data.user); $('#comment_body_').html(data.content); var s='<div class="feedbackCon"><div id="comment_body_" class="blog_comment_body">'+data.content +'</div></div>'; $('.comment_lou').append(s) } })} console.log('到评论页了'); {#当用户没有登录的时候, 提交评论的时候报错#} }else{ $('#comment_error').html('请登录在评论')} $('#tbCommentBody').val('') }); {# 回复#} {#在这儿创建一个全局的变量(在函数外创建的就是所有函数都能用)#} 这个变量是用于判断是否是子评论 var parent_comment_pk=''; $('.resp').click(function () { alert('ok1'); {# 点击回复按钮就能够跳转 将光标移动到这个输入评论的框内#} $('#tbCommentBody').focus(); {# 给评论框中写上初始的内容#} var rep1="@"+$(this).attr('creat_name')+'\n'; console.log(rep1); $('#tbCommentBody').val(rep1); {# 给全局的变量附上此次回复的楼层的值 #} parent_comment_pk=$(this).attr('lou') })


浙公网安备 33010602011771号