django-附件上传、media、extra、事务
1 普通上传
1.1 html
<form action="/index/" method="post" enctype="multipart/form-data"> {% csrf_token %} <p><input type="text" name="user" id="user"></p> <p><input type="file" name="myFile" id="file"></p> <input type="submit"> </form>
1.2 views
def index(request): if request.method == "POST": print(request.POST) print(request.FILES) file_obj = request.FILES.get("myFile") print(file_obj.name) with open(file_obj.name,"wb") as f: for line in file_obj: f.write(line) return HttpResponse("上传成功。") return render(request, "index.html")
2 基于ajax实现
2.1 Html
<p><input type="file" name="myFile" id="file"></p> {% csrf_token %} <button>ajaxSend</button> <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js "></script> <script> $("button").click(function () { var formdata = new FormData(); formdata.append("imgFile", $("#file")[0].files[0]); formdata.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val()); $.ajax({ url: "/upload_img/", type: "POST", data: formdata, processData: false, contentType: false, success: function (msg) { console.log(msg) } }) }) </script>
2.2 views
import os,json def upload_img(request): if request.is_ajax(): obj = request.FILES.get("imgFile") img_path = os.path.join("static","img",obj.name) with open(img_path,mode="wb") as f: for chunk in obj.chunks(): f.write(chunk) data = { "status" : True, "path" : img_path } return HttpResponse(json.dumps(data))
3 伪ajax上传
基于FormData
缺点:兼容性不好
优点:Ajax直接发送
伪Ajax,兼容性更好
iframe,天生局部刷新
form,天生整个页面刷新
3.1 html
<input type="text" placeholder="默认值看看刷新之后在不在" /> <form method="POST" target="uploadIframe" action="/upload_img2/" enctype="multipart/form-data"> {% csrf_token %} <input type="text" name="user" /> <a class="add-pub-btn pub-icons"> 上传 <input type="file" name="avatar" id="imgUrl" /> </a> <input type="submit" value="提交" /> </form> <iframe id="ifm" name="uploadIframe" onload="successCallback(this);" style="display: none;" ></iframe> <div id="imgList"></div> <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js "></script> <script> function successCallback(ths){ var response = ths.contentWindow.document.body.innerHTML; response = JSON.parse(response); console.log(response); var img = document.createElement('img'); img.src = "/" + response.data; $('#imgList').append(img); } </script>
3.2 views
def upload2(request): return render(request,"iframe_upload.html") def upload_img2(request): response = BaseResponse() try: obj = request.FILES.get("avatar") img_path = os.path.join("static","img",obj.name) with open(img_path,mode="wb") as f: for chunk in obj.chunks(): for chunk in obj.chunks(): f.write(chunk) except Exception as e: response.msg = str(e) else: request.status = True response.data = img_path return HttpResponse(json.dumps(response.get_dict()))
4 上传按钮美化
4.1 css
<style> .add-pub-btn { width: 62px; height: 31px; line-height: 31px; display: block; text-align: center; color: #fff; font-size: 14px; font-weight: 700; margin-top: 5px; cursor: pointer; } .pub-icons { background: url(/static/img/bottom.png?v=2.8) no-repeat 0 0; } #imgUrl { border: 0; filter: alpha(opacity=0); background: 0 0; opacity: 0; -moz-opacity: 0; width: 62px; height: 31px; left: 5px; top: 5px\9; position: absolute; cursor: pointer; } </style>
4.2 按钮设置
<a class="add-pub-btn pub-icons"> 上传 <input type="file" name="avatar" id="imgUrl" /> </a>
5 图片预览
本图片的预览功能,主要利用html.js的FileReader进行实现的
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注册</title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <style> #avatar { margin-top: 5px; margin-bottom: 5px; position: relative; width: 100px; height: 100px; } #avatar_img, #file { width: 100px; height: 100px; position: absolute; left: 15px; top: 0; } #file { opacity: 0; } </style> </head> <body> <div class="container"> <div class="row"> <div class="col-md-8" id="avatar"> <img src="default.png" class="img-thumbnail" id="avatar_img"> <input type="file" id="file"> </div> </div> </div> <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js "></script> <script type="text/javascript"> // 预览功能 $("#file").change(function () { var choose_file = $("#file")[0].files[0]; var reader = new FileReader(); reader.readAsDataURL(choose_file); reader.onload = function () { $("#avatar_img").attr("src", this.result) } }); </script> </body> </html>
6 文件上传路径
6.1 配置
在settings中配置
MEDIA_ROOT=os.path.join(BASE_DIR,"blog","media") MEDIA_URL="/media/"
在urls.py中配置
from django.views.static import serve url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
6.2 使用
<img src='/media/avatarDir/a.png'>
7 extra
有些情况下,Django的查询语法难以简单的表达复杂的 WHERE 子句,对于这种情况, Django 提供了 extra() QuerySet修改机制 — 它能在 QuerySet生成的SQL从句中注入新子句
extra可以指定一个或多个 参数,例如 select, where or tables. 这些参数都不是必须的,但是你至少要使用一个!要注意这些额外的方式对不同的数据库引擎可能存在移植性问题.(因为你在显式的书写SQL语句),除非万不得已,尽量避免这样做
# in sqlite: article_obj=models.Article.objects .filter(nid=1) .extra(select={"standard_time":"strftime('%%Y-%%m-%%d',create_time)"}) .values("standard_time","nid","title") print(article_obj) # <QuerySet [{'title': 'MongoDb 入门教程', 'standard_time': '2017-09-03', 'nid': 1}]> current_user = models.UserInfo.objects.filter(username=username).first() #当前用户 【每一步的分析过程】 1、models.Article.objects.all() #查出每一篇文章 2、models.Article.objects.all().filter(user=current_user) #查出当前用户的所有文章 3、models.Article.objects.all().filter(user=current_user).extra(select={"filter_create_date":"strftime('%%Y/%%m',create_time)"}).values_list("filter_create_date") #查出当前用户的所有文章的create_time,并且只取出年份和月份 解决方案:使用extra方法 extra使用来进行过滤的,参数select必须等于一个字典(转成sql的where语句去执行,查出create_time,然后转换成自己格式化的时间) 4、models.Article.objects.all().filter(user=current_user).extra(select={"filter_create_date":"strftime('%%Y/%%m',create_time)"}).values_list("filter_create_date").annotate(Count("title")) #按照查询出来的年份和月份进行分组,并且显示文章个数
8 事务使用
from django.contrib.auth import authenticate with transaction.atomic(): models.ArticleUpDown.objects.create(user_id=user_id, article_id=article_id) models.Article.objects.filter(nid=article_id).update(up_count=F("up_count") + 1)