思路:
使用ajax方式將圖片和文本一起通過formData提交到后台,Django后台通過request.POST和request.FILES方式接收數據
1、前端代碼
{% extends 'base.html' %} {% load staticfiles %} {% block title %}POST ARTICLE{% endblock %} {% block content %} <div style="margin-left:10px"> <form class ="form-hoizontal" method ="post">{% csrf_token %} <div class="form-group" style="margin-top: 10px;"> <label for="avatar">標題圖</label> <input type="file" class="form-control-file" name="avatar" id="avatar"> </div> <div class ="row" style="margin-top: 10px;"> <div class="col-md-2 text-right "><span>標題:</span></div> <div class="col-md-10 text-left ">{{article_post_form.title}}</div> </div> <div class ="row" style=" margin-top: 10px;"> <div class="col-md-2 text-right"><span>欄目:</span></div> <div class="col-md-10 text-left"> <select id="which_column"> {% for column in article_columns %} <option value=" {{column.id }}">{{column.column}}</option> {% endfor %} </select> </div> </div> <div class="row" style="margin-top: 10px"> <div class="col-md-2 text-right"><span>標簽:</span></div> <div class="col-md-10 text-left"> {% for tag in article_tags %} <input type="checkbox" value="{{ tag.tag }}">{{ tag.tag }}</input> {% endfor %} </div> </div> <div class ="row" style="margin-top:10px;"> <div class=" col-md-2 text-right"><span >內容:</span></div> <div id="editormd" class=" col-md-10 text-left "> <textarea style="display: none;" id="id_body"></textarea> </div> </div> <div class ="row"> <input type="button" class="btn btn-primary btn-lg" value="發布" onclick="publish_article()" > </div> </form> </div> <script type="text/javascript" src='{% static "js/jquery.js"%}'></script> <script type="text/javascript" src="{% static 'js/layer.js'%}"></script> <script type="text/javascript" src="{% static 'editor/editormd.min.js' %}"></script> <script type="text/javascript" src="{% static "js/ajaxfileupload.js" %}"></script> <script type="text/javascript"> $(function () { var editor = editormd("editormd",{ width:"100%", height:640, syncScrolling:"single", path:"{% static 'editor/lib/' %}" }); }); </script> <link rel="stylesheet" href="{% static 'editor/css/style.css' %}"> <link rel="stylesheet" href="{% static 'editor/css/editormd.css' %}"> <!-- 執行上傳文件操作的函數 --> <script type="text/javascript"> function publish_article(){ var formData = new FormData(); var fileobj=$('#avatar')[0].files[0]; //注意這里的取值方式,獲取文件對象 formData.append('avatarrrrr', fileobj); {#此處的id=id_title是表單生成的,代碼並沒有編寫此屬性#} formData.append('title', $("#id_title").val()); formData.append('column_id', $("#which_column").val()); formData.append('body', $("#id_body").val()); $.ajax({ url:"{% url 'article:article_post' %}", {#一定不要寫成小寫了,坑了好久#} type: 'POST', {#mimeType: "multipart/form-data",#} {#告訴jQuery不要去處理發送的數據, 發送對象。#} processData : false, {#告訴jQuery不要去設置Content-Type請求頭#} contentType : false, async : false, data: formData, success:function (e) { if(e=='1'){ layer.msg("成功發布"); location.href = "{% url 'article:article_list' %}"; }else if(e=='2'){ layer.msg("sorry"); } else{ layer.msg("項目名和內容必須填寫"); } }, }); } </script> {% endblock %}
注意:
1、由於是post方式提交數據,form中不要忘了{% csrf_token %}
2、提交按鈕是input標簽,type="button",千萬不要把type=“submit”,否則會導致執行兩次后台邏輯
3、注意文件的取值方式 $('#avatar')[0].files[0],和獲取文本方式不太一樣,可以在瀏覽器console中測試驗證
4、文件和文本數據是使用formData存儲的
2、model中需要加上圖片字段
upload_to參數代表將圖片文件放在哪里,%Y%m%d是格式化時間,創建一個當天年月日的文件夾,里面放圖片文件
3、修改forms.py
因為圖片也要存入數據庫,所以form中也要加上該字段
4、修改settings.py配置、URL配置
settings.py中加上媒體文件配置
# 媒體文件地址 MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
urls.py中加上
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
from django.conf.urls import url, include from django.contrib import admin from django.conf import settings from django.conf.urls.static import static urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^blog/', include('blog.urls', namespace='blog', app_name='blog')), url(r'^account/', include('account.urls', namespace='account', app_name='account')), url(r'^article/', include('article.urls', namespace='article', app_name='article')), ] urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
5、進行數據遷移
執行python manage.py makemigrations 和 python manage.py migrate進行數據遷移
6、修改后台代碼
@csrf_exempt @login_wrapper def article_post(request): ''' 文章發布功能 :param request: :return: ''' if request.method == 'POST': # print('已進入article_post視圖') print('request.FILES的值為:%s' % request.FILES) print('request.POST的值為:%s' % request.POST) # 實例化表單對象,來自於前端ajax請求,由於有文件傳輸,所以此處加上requesr.FILES article_post_form = ArticlePostForm(request.POST, request.FILES) if article_post_form.is_valid(): cd = article_post_form.cleaned_data try: # ModelForm 類或者它的子類都具有save()方法,當然實例化后的article_post_form也有此方法, # 它的效果是生成該數據對象,並將表單數據保存到數據庫 # commit=False則表示只生成文章數據對象,不保存 new_article = article_post_form.save(commit=False) # 給該文章數據對象設置作者和欄目后再進行保存 new_article.author = request.user new_article.column = request.user.article_column.get(id=request.POST['column_id']) print('正在更新文章到數據庫') new_article.avatar = request.FILES.get('avatarrrrr') # avatar = ArticlePost(avatar=request.FILES.get('avatar', None)) # print('avatar的值為:%s' % avatar.avatar) # print('request.POST的值為:%s' % request.POST) # print('request.FILES的值為:%s' % request.FILES) # print('request.FILES的值為:%s' % request.FILES.get('avatarrrrr')) print('即將保存') new_article.save() print('已經保存啦') return HttpResponse('1') except: return HttpResponse('2') else: return HttpResponse('不合法啊') else: article_post_form = ArticlePostForm() # 獲取request.user用戶的所有欄目article_column為ArticleColumn模型類中的user字段的related_name,其實等價於 # article_columns = ArticleColumn.objects.filter(user=request.user) # 通過user實例,找到其名下所有的ArticleColumn實例 article_columns = request.user.article_column.all() return render(request, 'article/column/article_post.html', {'article_post_form': article_post_form, 'article_columns': article_columns})
7、測試