本文是Django經典面試問題與答案系列的中篇,如果還未讀過第一篇的,請點擊這裡。小編精心收集,希望對大家學習和工作有所幫助,歡迎轉載點讚啊。
11. 簡單說說看 Django的CSRF防禦機制
Django的CSRF保護主要是通過django.middleware.csrf.CsrfViewMiddleware中間件來實現的。主要流程如下:
Django 第一次響應來自某個客戶端的get請求時,會在伺服器端隨機生成一個 csrftoken(一串64位的隨機字符串),把這個 token 放請求頭的 cookie 裡返回給用戶。
所有通過POST方式提交的表單在渲染時中必須包含一個 csrfmiddlewaretoken 隱藏欄位 (在模板中通過{% csrf_token %}標籤生成)。
當用戶通過POST提交表單時,Django會從請求頭cookie取csrftoken這一項的值,再從POST表單裡取csrfmiddlewaretoken交由中間件進行校驗兩者是否一致。如果一致表明這是一個合法請求,否則返回403 Forbidden.
注意csrftoken和csrfmiddlewaretoken並不是簡單相等的兩個字符串,而是通過算法判斷是否一致相等的,如下圖所示。
12. Django中使用AJAX發送POST請求時如何通過CSRF認證?
1. 第一種方式直接在發送數據中加入csrfmiddlewaretoken
<script>
$("#btn").on("click",function () {
$.ajax({
url:"/some_url/",
type:"POST",
data:{
csrfmiddlewaretoken:{{ csrf_token }}, //寫在模板中,才會被渲染
},
success:function (data) {
}
})
})
</script>
2.通過jquery選擇器獲取csrfmiddlewaretoken
<script>
$("#btn").on("click",function () {
$.ajax({
url:"/some_url/",
type:"POST",
data:{
csrfmiddlewaretoken:$('[name="csrfmiddlewaretoken"]').val(),
},
success:function (data) {
}
})
})
</script>
3. 使用jquery.cookie.js調用請求頭cookie中的csrftoken
<script src="/static/jquery.cookie.js"></script> //必須先引入它
<script>
$("#btn").on("click",function () {
$.ajax({
url:"/some_url/",
type:"POST",
headers:{"X-CSRFToken":$.cookie('csrftoken')},
data:$("#f1").serialize()
}
)
})
</script>
更多閱讀
Django基礎(17): 如何上傳處理文件及Ajax文件上傳示範(附GitHub源碼)
Django實戰: 利用AJAX技術實現博文實時搜索
13. 什麼情況下需要使用select_related和prefetch_related方法以及兩者的區別
當你查詢單個主對象或主對象列表並需要在模板或其它地方中使用到每個對象的關聯對象信息
時,請一定記住使用select_related和prefetch_related一次性獲取所有對象信息,從而提升
資料庫查詢效率,避免重複查詢。兩個方法都是Django ORM優化數據查詢必須要熟練掌握
的方法。
兩者的區別是:
對單對單(OneToOne)或單對多外鍵(ForeignKey)欄位,使用select_related方法
對於多對多欄位(ManyToMany)和反向外鍵關係,使用prefetch_related方法
select_related方法執行一次資料庫查詢,prefetch_related方法執行兩次資料庫查詢
使用Prefetch方法可以給prefetch_related方法額外添加額外條件和屬性。
更多閱讀
Django基礎(29):select_related和prefetch_related的用法與區別
14. 如何從數據表中獲取一個隨機對象?
可以使用order_by('?').first()隨機獲取一個對象
def get_random_object():
return MyModel.objects.order_by("?").first()
更多閱讀
Django ORM Cookbook精選摘錄(上)
15. 說說看aggregate和annotate方法的作用並舉幾個例子
aggregate的中文意思是聚合, 源於SQL的聚合函數。Django的aggregate()方法作用是對一組值
(比如queryset的某個欄位)進行統計計算,並以字典(Dict)格式返回統計計算結果。
django的aggregate方法支持的聚合操作有AVG / COUNT / MAX / MIN /SUM 等。
Student.objects.aggregate(Avg('age『), Max('age『), Min('age『))
# 同時獲取學生年齡均值, 最大值和最小值, 返回字典
{ 'age__avg': 12, 'age__max': 18, 'age__min': 6, }
Hobby.objects.aggregate(Max('student__age'))
# 根據Hobby反查學生最大年齡。查詢欄位student和age間有雙下劃線哦。
{ 'student__age__max': 12 }
annotate的中文意思是注釋,一個更好的理解是分組(Group By)。如果你想要對數據集先進行分組然後再進行某些聚合操作或排序時,需要使用annotate方法來實現。與aggregate方法不同的是,annotate方法返回結果的不僅僅是含有統計結果的一個字典,而是包含有新增統計欄位的查詢集(queryset).
# 按學生分組,統計每個學生愛好數量,並自定義欄位名
Student.objects.annotate(hobby_count_by_student=Count('hobbies'))
# 按愛好分組,再統計每組學生數量。
Hobby.objects.annotate(Count('student'))
# 按愛好分組,再統計每組學生最大年齡。
Hobby.objects.annotate(Max('student__age'))
# 先按愛好分組,再統計每組學生數量, 然後篩選出學生數量大於1的愛好。
Hobby.objects.annotate(student_num=Count('student')).filter(student_num__gt=1)
# 先按愛好分組,篩選出以'd'開頭的愛好,再統計每組學生數量。
Hobby.objects.filter(name__startswith="d").annotate(student_num=Count('student『))
更多閱讀
Django基礎(24): aggregate和annotate方法使用詳解與示例
16. Django中如何使用redis做緩存?
安裝好redis後,你需要安裝django-redis才能在django中使用redis。django-redis安裝命令如下:
settings.py中加入以下內容配置緩存。your_host_ip換成你的伺服器地址,yourpassword換成你的伺服器登陸密碼。
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://your_host_ip:6379',
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"PASSWORD": "yourpassword",
},
},
}
你還可以在settings.py設置緩存默認過期時間(非必須)
REDIS_TIMEOUT=7*24*60*60
更多閱讀
Django中如何使用Redis進行緩存詳細教程(含Windows系統下安裝redis)
17. Django項目上傳到代碼庫時是否需要忽略資料庫遷移文件?
資料庫遷移文件位於每個app文件夾的migrations文件夾裡,這些文件記錄了模型的創建與改
動。每次當你創建模型或對模型欄位進行修改,然後運行python manage.py
makemigrations命令時都會有新的遷移文件產生。Django官方文檔特別說明這些遷移文件
屬於Django項目代碼中很重要的一部分,不應刪除或忽略,所以建議上傳。
更多閱讀
Django項目上傳.gitignore文件建議忽略文件清單及是否需要忽略資料庫遷移文件
18. 如何在模板中獲取當前訪問url地址
在模板中你可以使用{{ request.path }}獲取當前url,如果要獲取帶querystring的完整url你可以使用{{ request.get_full_path }}。如果你要獲取完整絕對路徑,你可以使用 {{ request.build_absolute_uri }}。具體使用方法如下所示:
https://jackeygao.io/search/?keyword=django
Method
Output
request.path
/search/
request.get_full_path
search/?keyword=django
request.build_absolute_uri
https://jackeygao.io/search/?keyword=django
19. 使用F方法更新一個對象或多個對象的某個欄位有什麼優點?
通常情況下我們在更新數據時需要先從資料庫裡將原數據取出後放在內存裡,然後編輯某些欄位或屬性,最後提交更新資料庫。使用F方法則可以幫助我們避免將所有數據先載入內存,而是直接生成SQL語句更新資料庫。
假如我們需要對所有產品的價格漲20%,我們通常做法如下。當產品很少的時候,對網站性能沒影響。但如果產品數量非常多,把它們信息全部先載入內存會造成很大性能浪費。
products = Product.objects.all()
for product in products:
product.price *= 1.2
product.save()
使用F方法可以解決上述問題。我們直接可以更新資料庫,而不必將所有產品載入內存。
from django.db.models import F
Product.objects.update(price=F('price') * 1.2)
我們也可以使用F方法更新單個對象的欄位,如下所示:
product = Product.objects.get(pk=5009)
product.price = F('price') * 1.2
product.save()
但值得注意的是當你使用F方法對某個對象欄位進行更新後,需要使用refresh_from_db()方法後才能獲取最新的欄位信息(非常重要!)。如下所示:
product.price = F('price') + 1
product.save()
print(product.price) # <CombinedExpression: F(price) + Value(1)>
product.refresh_from_db()
print(product.price) # Decimal('13.00')
20. 說說 nginx 和 uWISG 伺服器之間如何配合工作的?
首先瀏覽器發起 http 請求到 nginx 伺服器,Nginx 根據接收到請求包,進行 url 分析,
判斷訪問的資源類型。如果是靜態資源,直接讀取靜態資源返回給瀏覽器。
如果請求的是動態資源就轉交給 uwsgi伺服器。
uwsgi 伺服器根據自身的uwsgi 和 WSGI 協議,找到對應的 Django 框架。
Django 框架下的應用進行邏輯處理後,將返回值發送到 uwsgi 伺服器。
uwsgi 伺服器再返回給 nginx,最後 nginx將返回值返回給瀏覽器進行渲染顯示給用戶。
未完待續
喜歡本文的,歡迎收藏和點讚。希望獲得更多乾貨的,別忘了關注我們的微信公眾號【Python Web與Django開發】並加星標哦。
大江狗
2020.4.19