19 Jun 18
一、作業講解(代碼統計)
# views.py
from django.shortcuts import HttpResponse,render,redirect
import shutil
import os
import uuid
# 導入settings的方式
from django.conf import settings
ACCEPT_FILE_TYPE = ['zip','tar','gztar','bztar','xztar','rar'] # 可以給一個全局變量,放在配置文件中,用之前導入
def upload(request):
if request.method == 'POST':
file_obj = request.FILES.get('file')
filename, suffix = file_obj.name.rsplit('.',maxsplit=1)
if suffix not in ACCEPT_FILE_TYPE: # 增加強健性
return HttpResponse('wrong file type')
with open(file_obj.name,'wb') as f:
for chunk in file_obj.chunks(): # 從上傳文件對象一點一點讀取數據
f.write(chunk)
real_file_path = os.path.join(settings.BASE_DIR,file_obj.name) # 拼接得到上傳文件的全路徑
upload_path = os.path.join(settings.BASE_DIR,'files',str(uuid.uuid4())) # 對上傳的文件做處理
shutil.unpack_archive(real_file_path,extract_dir=upload_path) # 解壓代碼文件至指定文件夾
total_num = 0
for (dir_path,dir_names,filenames) in os.walk(upload_path):
# os.walk() 用來遍歷所有的文件,可以拿到以下三個參數
# dir_path: 根目錄dir_names: 文件夾filenames: 文件
for filename in filenames:
file_path = os.path.join(dir_path,filename) # 將文件名和根目錄拼接成完整的路徑
file_path_list = file_path.rsplit('.',maxsplit=1)
if len(file_path_list) != 2:
continue
if file_path_list[1] != 'py':
continue
line_num = 0
with open(file_path,'r') as f:
for line in f:
if line.strip().startswith('#'):
continue
line_num += 1
total_num += line_num
return
render(request,'done.html',{'file_name':file_obj.name,'file_size':file_obj.size,'total_num':total_num})
return render(request,'upload.html')
二、內容補充
目前,this和箭頭函數一起使用可能出現問題。所以,推薦盡量少用箭頭函數;但要能看懂。
三、今日內容
- 模版語言剩下的
http://www.cnblogs.com/liwenzhou/p/7931828.html
- csrf_token: 用於跨站請求偽造保護。是Django提供的一個解決方案:在提交表單時帶着之前Django給該頁面生成的token,如果沒有token,或token匹配失敗,將拒絕繼續訪問;這樣,釣魚網站就不可以通過單單設置action,而跳轉至正經網站某個頁面,進而修改正經網站的數據庫。
在頁面的form表單里面寫上{% csrf_token %},在settings中即可不注釋csrf相關
#釣魚網站html
<h1>這是一個釣魚網站</h1>
<formaction="http://127.0.0.1:8000/zhuanzhang/"method="post">
# action直接跳轉到別的網站
<p>轉給誰:<input type="text"></p>
<p><input style="display: none" type="text" name="id" value="3"></p>
<p>轉多少:<input type="text" name="num"></p>
<p>密碼:<input type="password" name="pwd"></p>
<p><input type="submit" value="提交"></p>
</form>
#正經網站html
<h1>這是一個正經網站</h1>
<formaction="/zhuanzhang/"method="post">
{% csrf_token %} # 阻止跨站請求偽造
<p>轉給誰:<input type="text" name="id"></p>
<p>轉多少:<input type="text" name="num"></p>
<p>密碼:<input type="password" name="pwd"></p>
<p><input type="submit" value="提交"></p>
</form>
ps:如果不設置數據庫,使用默認的數據庫db.sqlite3
- 靜態文件相關(取代硬編碼(/static/…))
如果有改static這個名字的需求,用硬編碼要通篇改;如果使用以下方式,則不存在這個問題;一般來說,上述需求比較不常見
{% load static %}
<img src="{% static "images/hi.jpg" %}" alt="Hi!" />
引用JS文件時使用:
{% load static %}
<script src="{% static "mytest.js" %}"></script>
某個文件多處被用到可以存為一個變量
{% load static %}
{% static "images/hi.jpg" as myphoto %}
<img src="{{ myphoto }}"></img>
- get_static_prefix
# 極少使用
{% load static %}
<img src="{% get_static_prefix %}images/hi.jpg" alt="Hi!" />
{% load static %}
{% get_static_prefix as STATIC_PREFIX %}
<img src="{{ STATIC_PREFIX }}images/hi.jpg"alt="Hi!" />
<img src="{{ STATIC_PREFIX }}images/hi2.jpg" alt="Hello!" />
- 自定義simpletag和自定義filter類似,只不過接收更靈活的參數。
自定義的filter,simpletag和inclusion_tag都要放在templatetags 這個新建的package中的py文件下
filter: {{ }} 在變量的基礎上做額外的調整
simpletag {% %} 可傳多個參數,返回它們之間所做運算的結果
定義注冊simple tag
@register.simple_tag(name="plus")
def plus(a, b, c):
return "{} + {} + {}".format(a, b, c)
使用自定義simple tag
{% load app01_demo %}
{% plus "1" "2" "abc" %}
- inclusion_tag:多用於返回html代碼片段;后續項目會使用
# templatetags/my_inclusion.py
from django import template
register = template.Library()
@register.inclusion_tag('result.html')
def show_results(n):
n = 1 if n < 1 else int(n)
data = ["第{}項".format(i) for i in range(1, n+1)]
return {"data": data}
templates/snippets/result.html
<ul>
{% for choice in data %}
<li>{{ choice }}</li>
{% endfor %}
</ul>
templates/index.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>inclusion_tag test</title>
</head>
<body>
{% load inclusion_tag_test %}
{% show_results 10 %}
</body>
</html>
- urls.py(路由系統)
http://www.cnblogs.com/liwenzhou/p/8271147.html
a. URLconf配置
# 基本格式:
from django.conf.urls import url
urlpatterns = [
url(正則表達式, views視圖函數,參數,別名),
]
# 在Django2.0 中用path替換了url(from django.urls import path)
b. 正則表達式詳解
1)urlpatterns中的元素按照書寫順序從上往下逐一匹配正則表達式,一旦匹配成功則不再繼續。
2)若要從URL中捕獲一個值,只需要在它周圍放置一對圓括號(分組匹配)。
3)不需要添加一個前導的反斜杠,因為每個URL 都有。例如,應該是^articles 而不是^/articles。
# Django settings.py配置文件中默認沒有APPEND_SLASH 這個參數,但 Django 默認這個參數為APPEND_SLASH = True。 其作用就是自動在網址結尾加'/'。可設置APPEND_SLASH = False,改變默認值。
4)每個正則表達式前面的'r' 是可選的但是建議加上。
c. 正則匹配的模式
1) 分組匹配 --> 調用視圖函數的時候額外傳遞位置參數;正則表達式分組匹配(通過圓括號)來捕獲URL中的值並以位置參數形式自動傳遞給視圖的args。
# *args, agrs = (a,b)
url(r'^articles/([0-9]{4})/$', views.year_archive),
2) 分組命名匹配 --> 調用視圖函數的時候額外傳遞關鍵字參數
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
注意:
a) 要么全都用分組匹配,要么全都用分組命名匹配,不要混着用!
b) Django utl正則表達式匹配的位置:從第一個斜線到問號之前這一段的路徑
c) URL正則表達式捕獲的值都是字符串類型,如果要參與后續運算,應先進行類型轉換。
d) 可以給視圖函數的參數設置默認值
# 正則匹配時,不論是否分組\帶參數,即都可以調用views中的page方法
# urls.py中
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/$', views.page),
url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
]
# views.py中,可以為num指定默認值
def page(request, num="1"):
pass
d. include 分級路由(級級匹配:/app01/upload; 在第一級匹配app01,在第二級匹配upload)
# 推薦在各個app下建立自己的urls.py
查找的順序:請求--> project/urls.py --> app/urls.py --> app/views.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^blog/', include('blog.urls')), # 可以包含其他的URLconfs文件
]
e. 傳遞額外的參數給視圖函數
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]
f. URL匹配規則的別名(命名URL和URL反向解析(別名->正則表達式(URL)))
1) 起別名是為了,增加代碼的健壯性,不將URL硬編碼到代碼中!
2) 用法
a) 在views.py中如何根據別名找到url
from django.urls import reverse
url = reverse('別名')
b) 在模板語言中如何根據別名找到url
{% url '別名' %}
3) 帶參數的url如何反向生成?
a) 位置參數
i) 在views.py中:
reverse("別名", args=(參數1, 參數2, ...))
ii) 在模板語言中:
{% url "別名" 參數1, 參數2... %}
b). 關鍵字參數
i) 在views.py中:
reverse("別名", kwargs={"k1":參數1, ...})
ii) 在模板語言中:
{% url "別名" 參數1, 參數2... %}
# 在模版語言中,無法傳遞關鍵字參數,只能根據位置,依次傳參
4) namespace(命名空間), 是include的一個參數
# 使用include語法,將其他的urls.py 包含進來
from django.conf.urls import url, include
urlpatterns = [
url(r'^app01/', include('app01.urls', namespace='app01')),
url(r'^app02/', include('app02.urls', namespace='app02')),
]
語法:'命名空間名稱:URL名稱'
# 這樣兩個app中url名稱重復了,反轉URL的時候就可以通過命名空間的名稱得到當前的URL;即使app中URL的命名相同,也可以反轉得到正確的URL了。
模板中使用:
{% url 'app01:detail' pk=12 pp=99 %}
views中的函數中使用
v = reverse('app01:detail', kwargs={'pk':11})
四、今日作業
用一個函數一個URL匹配模式實現 書書籍表、作者表、出版社表的展示和刪除操作
關鍵點:
- URL匹配模式的設計(分組匹配或分組命名匹配;給URL匹配模式起別名)
2. 反射:由一個字符串,找到對應的類變量
3. URL的反向解析(別名--> 完整的URL)
4. 正則表達式
import re
# 寫一個正則表達式, 只能從add delete edit list 這四個單次里面選一個
s1 = "delete" # 匹配成功
s2 = "cut" # 匹配不成功
r = re.compile(r'add|delete|edit|list')
print(r.match(s1))
print(r.match(s2))
# urls.py
url(r'(?P<operation>list|delete)_(?P<table_name>[a-zA-Z]+)/', views.op, name = 'list_delete'),
# views.py
def op(request,operation,table_name):
table = table_name.capitalize()
if hasattr(models,table):
class_obj = getattr(models,table)
if operation.upper() == 'LIST':
ret = class_obj.objects.all()
return render(request,'{}_{}.html'.format(table_name,operation),{'ret':ret})
elif operation.upper() == 'DELETE':
id = request.GET.get('id')
class_obj.objects.get(id=id).delete()
url = reverse('list_delete', kwargs={'operation':'list','table_name':table_name})
return redirect(url)