settings.py,html
ALLOWED_HOSTS = ['*'] INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] STATICFILES_DIRS = ( os.path.join(BASE_DIR,'static') )
urls.py,python
url(r'^upload/', views.upload),
views.py,jquery
import os def upload(request): if request.method == 'POST': username = request.POST.get('username',None) img = request.FILES.get('img',None) #圖片不是字符串,因此用wb模式寫入 f = open(os.path.join('static/img/',img.name),'wb') for chun in img.chunks(): f.write(chun) f.close() print(username,img) return render(request,'upload.html')
upload.html,ajax
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form class="form-file" action="/upload/" method="post" enctype="multipart/form-data"> <input type="text" name="username" /> <input type="file" name="img" /> <input type="submit" value="submit" /> </form> </body> </html>
原生Ajax的做用,好比手機app,好多都是走的移動流量,那導入一個jquery.js文件就得1m,每次執行每次都導入每次都消耗1m流量,就不如用原生Ajax更合適了。chrome
setting.py就是常規配置;數據庫
urls.py,django
url(r'^upload/', views.upload),
views.py,json
import os def upload(request): if request.method == 'POST': username = request.POST.get('user',None) img = request.FILES.get('img',None) f = open(os.path.join('static/img/',img.name),'wb') for chun in img.chunks(): f.write(chun) f.close() print(username,img) return render(request,'upload.html')
upload.html,瀏覽器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .img{ width: 300px; height: 300px; } </style> </head> <body> <input type="text" id="user" name="user" /> <input type="file" id="img" name="img" /> <a onclick="uploadFile1();" >XMLHttpRequet上傳</a> <script src="/static/js/jquery-1.12.4.js"></script> <script> function uploadFile1(){ // 建立表單對象 var form = new FormData(); // 在表單對象中添加:user: 用戶輸入的用戶名 form.append('user',document.getElementById('user').value); // 在表單對象中添加:img: 文件對象 var fileObj = document.getElementById("img").files[0]; form.append("img", fileObj); var xhr = new XMLHttpRequest(); // 回調函數,當Ajax請求狀態變化時,自動觸發 xhr.onreadystatechange = function(){ // xhr.readyState=4 表示,客戶端已經將服務器端響應的內容所有獲取完畢 if(xhr.readyState == 4){ // xhr.responseText 獲取服務器端響應的文本內容,即: views中 return HttpResponse中的內容 var data = xhr.responseText; console.log(data); } }; // 建立異步鏈接 xhr.open("post", '/upload/', true); // 發送請求,將form中的數據發送到服務器端 xhr.send(form); } </script> </body> </html>
var i = document.getElementById('i1');
var j = $('#i1');安全
$(i) #dom轉jquery
j[0] #jquery轉dom
document.getElementById('img').files[0] 等價於 $('#img')[0].files[0]
upload.html,
function uploadFile2(){ // jQuery對象和dom對象 var fileObj = $("#img")[0].files[0]; var form = new FormData(); form.append("img", fileObj); form.append("user", 'alex'); $.ajax({ type:'POST', url: '/upload/', data: form,// # {'k1': ;'v1'} > send('k1=v1') processData: false, // tell jQuery not to process the data contentType: false, // tell jQuery not to set contentType success: function(arg){ console.log(arg); } }) }
不管是原生ajax方式仍是jquery方式上傳文件,都須要「new FormData()」,而老的瀏覽器是不支持「new FormData()」,爲了兼容性,就要用iframe方式上傳文件,iframe方式支持任何版本的瀏覽器。
urls.py,
url(r'^upload/', views.upload),
views.py,
from django.shortcuts import render,HttpResponse,redirect # Create your views here. import os,json def upload(request): if request.method == 'POST': try: ret = {'status':False,'data':'','error':''} username = request.POST.get('user',None) img = request.FILES.get('img',None) file_path = os.path.join('static/img/',img.name) f = open(file_path,'wb') for chun in img.chunks(): f.write(chun) f.close() ret['status'] = True ret['data'] = file_path except Exception as e: ret['error'] = e print(username,img) return HttpResponse(json.dumps(ret)) # return HttpResponse('ok') return render(request,'upload.html')
upload.html,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .img{ width: 300px; height: 300px; } </style> </head> <body> #定義一個iframe,它僅僅做爲一個通道,不用顯示出來,因此display:none。 <iframe id="my_iframe" name="my_iframe" style="display: none" src=""></iframe> <form id="fo" method="POST" action="/upload/" enctype="multipart/form-data"> <input type="text" id="user" name="user" /> #onchange,當檢測到這個input變化(文件從無到有、更換文件)後,就自動執行函數。 <input type="file" id="img" name="img" onchange="uploadFile3();" /> <input type="submit" /> </form> <div id="filesee"> </div> <a onclick="uploadFile3();" >測試Iframe</a> <script src="/static/js/jquery-1.12.4.js"></script> <script> function uploadFile3(){ #先移除舊圖片,否則會依次顯示全部圖片 $('#filesee').find('img').remove(); #找到一個元素.onload等價於「onload=function()」。 document.getElementById('my_iframe').onload = callback; #target後面的'my_iframe'是上面iframe的name值,而不是id值;將數據以iframe爲通道提交,由於iframe能夠實現只刷新本身的框,不影響頁面的其餘元素,給用戶的視覺效應就是網頁沒刷新。 document.getElementById('fo').target = 'my_iframe'; document.getElementById('fo').submit(); } function callback(){ #iframe實際上是一個完整的、單獨的html代碼,因此須要加一個「contents()」 var text = $('#my_iframe').contents().find('body').text() var text = JSON.parse(text) #若是返回true,就顯示圖片,不然報警。 if(text.status) { var file_path = '/' + text.data var tag = document.createElement('img'); tag.src = file_path; $('#filesee').append(tag); } else{ alert(text.error); } } </script> </body> </html>
用戶上傳文件後,文件存在硬盤裏,當點擊發布時,將圖片的路徑和描述內容保存到數據庫。
img對象裏有一個「size」參數,能夠用此來限制圖片大小。
下面的代碼去掉了一些代碼,因此運行可能有點問題,根據狀況修改。
若是隻是文本驗證碼,那很不安全,避免不了暴力破解。
import requests r1 = requests.get('www.sfbest.com') print(r1.text)#這裏的r1.text就是www.sfbest.com的源代碼,從源代碼裏就能獲取到「文本驗證碼」,而後requests.post('www.sfbest.com','{useranme:123,pwd:345,check_code:345ig}'),這樣就輕鬆無限訪問網站(好比搶票)。
urls.py,
url(r'^get_check_code/', views.get_check_code),
url(r'^loginauth/', views.loginauth),
check_code.py(放在app同級目錄的backend下),
#!/usr/bin/env python #coding:utf-8 import random from PIL import Image, ImageDraw, ImageFont, ImageFilter _letter_cases = "abcdefghjkmnpqrstuvwxy" # 小寫字母,去除可能干擾的i,l,o,z _upper_cases = _letter_cases.upper() # 大寫字母 _numbers = ''.join(map(str, range(3, 10))) # 數字 init_chars = ''.join((_letter_cases, _upper_cases, _numbers)) def create_validate_code(size=(120, 30), chars=init_chars, img_type="GIF", mode="RGB", bg_color=(255, 255, 255), fg_color=(0, 0, 255), font_size=18, font_type="Monaco.ttf", #字體,放到app同級目錄 length=4, draw_lines=True, n_line=(1, 2), draw_points=True, point_chance = 2): ''' @todo: 生成驗證碼圖片 @param size: 圖片的大小,格式(寬,高),默認爲(120, 30) @param chars: 容許的字符集合,格式字符串 @param img_type: 圖片保存的格式,默認爲GIF,可選的爲GIF,JPEG,TIFF,PNG @param mode: 圖片模式,默認爲RGB @param bg_color: 背景顏色,默認爲白色 @param fg_color: 前景色,驗證碼字符顏色,默認爲藍色#0000FF @param font_size: 驗證碼字體大小 @param font_type: 驗證碼字體,默認爲 ae_AlArabiya.ttf @param length: 驗證碼字符個數 @param draw_lines: 是否劃干擾線 @param n_lines: 干擾線的條數範圍,格式元組,默認爲(1, 2),只有draw_lines爲True時有效 @param draw_points: 是否畫干擾點 @param point_chance: 干擾點出現的機率,大小範圍[0, 100] @return: [0]: PIL Image實例 @return: [1]: 驗證碼圖片中的字符串 ''' width, height = size # 寬, 高 img = Image.new(mode, size, bg_color) # 建立圖形 draw = ImageDraw.Draw(img) # 建立畫筆 def get_chars(): '''生成給定長度的字符串,返回列表格式''' return random.sample(chars, length) def create_lines(): '''繪製干擾線''' line_num = random.randint(*n_line) # 干擾線條數 for i in range(line_num): # 起始點 begin = (random.randint(0, size[0]), random.randint(0, size[1])) #結束點 end = (random.randint(0, size[0]), random.randint(0, size[1])) draw.line([begin, end], fill=(0, 0, 0)) def create_points(): '''繪製干擾點''' chance = min(100, max(0, int(point_chance))) # 大小限制在[0, 100] for w in range(width): for h in range(height): tmp = random.randint(0, 100) if tmp > 100 - chance: draw.point((w, h), fill=(0, 0, 0)) def create_strs(): '''繪製驗證碼字符''' c_chars = get_chars() strs = ' %s ' % ' '.join(c_chars) # 每一個字符先後以空格隔開 font = ImageFont.truetype(font_type, font_size) font_width, font_height = font.getsize(strs) draw.text(((width - font_width) / 3, (height - font_height) / 3), strs, font=font, fill=fg_color) return ''.join(c_chars) if draw_lines: create_lines() if draw_points: create_points() strs = create_strs() # 圖形扭曲參數 params = [1 - float(random.randint(1, 2)) / 100, 0, 0, 0, 1 - float(random.randint(1, 10)) / 100, float(random.randint(1, 2)) / 500, 0.001, float(random.randint(1, 2)) / 500 ] img = img.transform(size, Image.PERSPECTIVE, params) # 建立扭曲 img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 濾鏡,邊界增強(閾值更大) return img, strs
loginauth.html,
<div class="checkcode hide"> <img src="/get_check_code/" onclick="playcheckcode(this);"/> <input type="text" name="checkcodevalue" placeholder="驗證碼" /> </div> <script> function playcheckcode(ths){ #每次在src後加一個問號,url變了就會從新提交一次請求,這樣就實現了點擊圖片換驗證碼的功能。 var new_src = $(ths).attr('src') + '?'; $(ths).attr('src',new_src) } </script>
views.py,
def get_check_code(request): #導入check_code.py from backend import check_code as CheckCode import io stream = io.BytesIO() img, code = CheckCode.create_validate_code() img.save(stream, "png") #將驗證碼的內容值保存到session裏,而後讀取這個值,跟用戶輸入的比較,若是錯誤就反饋驗證碼錯誤。 request.session["CheckCode"] = code return HttpResponse(stream.getvalue()) def loginauth(request): #此處代碼驗證用戶輸入的帳號、密碼、驗證碼可用性。
models.py,
from django.db import models # Create your models here. #發送註冊信息的臨時表(將驗證碼發給用戶郵箱或者用戶手機) class SendMsg(models.Model): nid = models.AutoField(primary_key=True) #自增id code = models.CharField(max_length=6) #驗證碼內容 email = models.CharField(max_length=32, db_index=True) #郵箱或手機號 times = models.IntegerField(default=0) #發送的次數 ctime = models.DateTimeField() #建立時間(用以比較用戶輸入驗證碼時該驗證碼是否已過時) #用戶信息表 class UserInfo(models.Model): nid = models.AutoField(primary_key=True) #自增id username = models.CharField(max_length=32, unique=True) #用戶名 password = models.CharField(max_length=32) #密碼 email = models.CharField(max_length=32, unique=True) #郵箱 ctime = models.DateTimeField() #建立時間 #新聞類型表 class NewsType(models.Model): nid = models.AutoField(primary_key=True) #自增id caption = models.CharField(max_length=32) #新聞類型 # 1 42區 # 2 段子 # 3 兔皮納 # 4 挨踢 # 5 你問我答 #新聞表 class News(models.Model): nid = models.AutoField(primary_key=True) #自增id user_info = models.ForeignKey('UserInfo') #將用戶表與新聞表關聯,哪一個用戶發表的該新聞 news_type = models.ForeignKey('NewsType') #將新聞類型表與新聞表關聯,該新聞屬於哪一個類型 title = models.CharField(max_length=32, db_index=True) #新聞標題 url = models.CharField(max_length=128) #新聞的url或者圖片的本地地址 content = models.CharField(max_length=50) #摘要 favor_count = models.IntegerField(default=0) #點贊個數 comment_count = models.IntegerField(default=0) #評論個數 ctime = models.DateTimeField() #建立時間 #點贊表 class Favor(models.Model): nid = models.AutoField(primary_key=True) #自增id user_info = models.ForeignKey('UserInfo') #與用戶表關聯,哪一個用戶點的贊,同一用戶,第一次點贊是加1,第二次點贊就是減1了,不能無限點贊 news = models.ForeignKey('News') #與新聞表關聯,給哪條新聞點讚的 ctime = models.DateTimeField() #建立時間 class Meta: unique_together = (("user_info", "news"),) #評論表 class Comment(models.Model): nid = models.AutoField(primary_key=True) #自增id user_info = models.ForeignKey('UserInfo') #與用戶表關聯 news = models.ForeignKey('News') #與新聞表關聯 up = models.IntegerField(default=0) #頂 down = models.IntegerField(default=0) #踩 ctime = models.DateTimeField() #建立時間 device = models.CharField(max_length=16) #設備(手機、pad、chrome、firefox等) content = models.CharField(max_length=150) #評論的內容 reply_id = models.ForeignKey('Comment', related_name='b', null=True, blank=True) #爲了實現評論樹的字段