上傳頭像跟上傳文件同樣,可是平時的應用中,咱們都是直接點擊一張圖片,就會跳出相似於input標籤中type爲file的樣式,這個實現就用到了label標籤的特性,經過label標籤的關聯特性,咱們能夠將一張圖片包在label標籤中,而且將input標籤隱藏掉,就能夠實現點擊圖片,打開的是input的標籤。html
具體代碼的實現:(基於bootstrap的實現)jquery
<div>
<label class="col-sm-2 control-label">頭像</label>
<div class="col-sm-8"> <label for="id_avatar"><img src="/static/avatars/default.png" alt="圖像加載失敗"></label> <input type="file" id="id_avatar" name="file" style="display:none"> </div>
</div>
實現了這個替換後,咱們在使用時,就會發現,選擇了圖片後,不能顯示,因此咱們就要針對這個來實現預覽功能ajax
預覽功能的實現:數據庫
<div class="form-group"> <label class="col-sm-2 control-label">頭像</label> <div class="col-sm-8"> <label for="id_avatar"><img id="avatar-img" src="/static/img/default.png" alt=""></label> <input accept="image/*" type="file" name="avatar" id="id_avatar" style="display: none"> <span class="help-block"></span> </div> </div> <script src="/static/jquery-3.3.1.js"></script> <script src="/static/bootstrap/js/bootstrap.min.js"></script> <script> // 找到頭像的input標籤綁定change事件 $("#id_avatar").change(function () { // 1. 建立一個讀取文件的對象 var fileReader = new FileReader(); // 取到當前選中的頭像文件 // console.log(this.files[0]); // 讀取你選中的那個文件 fileReader.readAsDataURL(this.files[0]); // 讀取文件是須要時間的 fileReader.onload = function () { // 2. 等上一步讀完文件以後才 把圖片加載到img標籤中 $("#avatar-img").attr("src", fileReader.result); }; });
備註:django
文件的讀取是須要時間的,因此必須使用onload方法進行等待文件的讀取完成bootstrap
此外,使用this.files獲得的是一個對象,取0獲得的是這個文件。後端
咱們也能夠在輸入文件的那個input框中添加一個屬性:accept 好比accept="image/png",表示一個默認的格式。app
預覽功能實現後,當用戶確認選擇,進行上傳時,就須要進行後端的存儲操做函數
備註:使用form表單進行向後端的提交帶文件的數據時,須要指定form表單的提交屬性 在form表單中加上enctype屬性 enctype=multipart/form-data,一樣的使用ajax向後端提交帶文件的數據時也須要相似的屬性:1.添加兩個屬性processData:false,contentType:false 2.data必須是FormData()類型post
以Django爲例,使用ajax實現向後端的提交
ajax代碼實現:
// AJAX提交註冊的數據
$("#reg-submit").click(function () {
// 取到用戶填寫的註冊數據,向後端發送AJAX請求
var formData = new FormData();
formData.append("username", $("#id_username").val());
formData.append("password", $("#id_password").val());
formData.append("re_password", $("#id_re_password").val());
formData.append("email", $("#id_email").val());
formData.append("avatar", $("#id_avatar")[0].files[0]);
formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val());
$.ajax({
url: "/reg/",
type: "post",
processData: false,
contentType: false,
data: formData,
success:function (data) {
if (data.status){
// 有錯誤就展現錯誤
// console.log(data.msg);
// 將報錯信息填寫到頁面上
$.each(data.msg, function (k,v) {
// console.log("id_"+k, v[0]);
// console.log($("#id_"+k));
$("#id_"+k).next("span").text(v[0]).parent().parent().addClass("has-error");
})
}else {
// 沒有錯誤就跳轉到指定頁面
location.href = data.msg;
}
}
})
});
// 將全部的input框綁定獲取焦點的事件,將全部的錯誤信息清空
$("form input").focus(function () {
$(this).next().text("").parent().parent().removeClass("has-error");
})
視圖函數部分的實現:
# 註冊的視圖函數 def register(request): if request.method == "POST": ret = {"status": 0, "msg": ""} form_obj = forms.RegForm(request.POST) print(request.POST) # 幫我作校驗 if form_obj.is_valid(): # 校驗經過,去數據庫建立一個新的用戶 form_obj.cleaned_data.pop("re_password") avatar_img = request.FILES.get("avatar") models.UserInfo.objects.create_user(**form_obj.cleaned_data, avatar=avatar_img) ret["msg"] = "/index/" return JsonResponse(ret) else: print(form_obj.errors) ret["status"] = 1 ret["msg"] = form_obj.errors print(ret) print("=" * 120) return JsonResponse(ret) # 生成一個form對象 form_obj = forms.RegForm() print(form_obj.fields) return render(request, "register.html", {"form_obj": form_obj})
備註:上傳的文件名有重複時,Django內部會自動在文件名後加一個隨機的字符串作區分,並在數據庫存儲。
另外,在Django中咱們用到了form組件的一些用法
from django import forms from blog import models from django.core.exceptions import ValidationError # from django.core.validators import RegexValidator # mobile = forms.CharField(validators=[RegexValidator('regex','哈哈哈')]) class RegForm(forms.Form): username=forms.CharField(label='用戶名',max_length=12,error_messages={'required':'不能爲空'},widget=forms.widgets.TextInput(attrs={'class':'form-control','placeholder':'請輸入用戶名'})) password = forms.CharField(label='密碼',min_length=6,error_messages={'min_length':'密碼最少爲六位','required':'不能爲空'},widget=forms.widgets.PasswordInput(attrs={'class':'form-control','placeholder':'請輸入密碼'})) re_password = forms.CharField(label='確認密碼',min_length=6,error_messages={'min_length':'確認密碼最少爲六位','required':'不能爲空'},widget=forms.widgets.PasswordInput(attrs={'class':'form-control','placeholder':'請輸入確認密碼'})) email = forms.EmailField(label='郵箱',error_messages={'required':'不能爲空','invalid':'格式錯誤'},widget=forms.widgets.EmailInput(attrs={'class':'form-control','placeholder':'請輸入郵箱'})) def clean(self): password = self.cleaned_data.get('password') re_password = self.cleaned_data.get('re_password') if re_password: if password !=re_password: self.add_error('re_password',ValidationError('兩次密碼不一致')) else: self.cleaned_data.pop('re_password') return self.cleaned_data def clean_username(self): username = self.cleaned_data.get('username') is_exists = models.UserInfo.objects.filter(username=username) if is_exists: self.add_error('username',ValidationError('用戶名已存在')) return username def clean_email(self): email = self.cleaned_data.get('email') is_exist = models.UserInfo.objects.filter(email=email) if is_exist: self.add_error('email',ValidationError('郵箱已存在')) else: return email
備註:label標籤的特殊用法:
<!--label的兩種用法--> <!--用法一:正經常使用法 實現關聯--> <label for="d1">用戶:</label> <input type="text" id="d1"> <!--用法二:將input標籤包到label標籤裏面也能夠實現聯動效果--> <label>用戶名 <input type="text"></label>
用戶上傳的文件,Django都叫media文件
若是要在頁面中展現出頭像,若是上傳文件的路徑在static目錄下,就會在頁面展現出來,不然,就沒法展現,由於settings.py 文件中沒有設置文件訪問路徑。
以下圖:這樣配置上傳文件的路徑,就能夠直接在頁面中展現出來
若是放在了其餘路徑下,就要一些相應的配置
Django給咱們提供了這種功能,只須要配置好media就能夠
1. settings.py中:
#BASE_DIR是Django中的項目的絕對路徑
#只須要在settings中添加這些就能夠
MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR,'media')
2.路由 urls.py 中的配置:
from django.views.static import serve from django.conf import settings #在路由中添加路徑 url(r'^media/(?P<path>.*)$', serve, {"document_root": settings.MEDIA_ROOT}),