基礎要點
render傳回一個html頁面,并且還能夠給該頁面傳資料
render内部原理
from django.template import Template,Context
def index(request):
temp = Template('<h1>{{ user }}</h1>')
con = Context({"user":{"name":'jason',"password":'123'}})
res = temp.render(con)
return HttpResponse(res)
FBV與CBV
視圖函數并不隻是指函數 也可以是類
- FBV(基于函數的視圖) 面向函數式程式設計
- CBV(基于類的視圖) 面向對象式程式設計
問題:基于CBV的視圖函數
get請求來就會走類裡面get方法,post請求來就會走類裡面post方法 ,為什麼???
# urls.py中
url(r'^login/',views.MyLogin.as_view())
# views.py中
from django.views import View
class MyLogin(View):
def get(self,request):
print("from MyLogin get方法")
return render(request,'login.html')
def post(self,request):
return HttpResponse("from MyLogin post方法")
研究方向
1.從url入手
url(r'^login/',views.MyLogin.as_view())
由于函數名加括号執行優先級最高,是以這一句話一寫完會立刻執行as_view()方法
@classonlymethod
def as_view(cls, **initkwargs): # cls就是我們自己的寫的類 MyLogin
def view(request, *args, **kwargs):
self = cls(**initkwargs) # 執行個體化産生MyLogin的對象 self = MyLogin(**ininkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
# 上面的幾句話都僅僅是在給對象新增屬性
return self.dispatch(request, *args, **kwargs) # dispatch傳回什麼 浏覽器就會收到什麼
# 對象在查找屬性或者方法的時候 你一定要默念 先從對象自己這裡找 然後從産生對象的類裡面找 最後類的父類依次往後
return view
通過源碼發現url比對關系可以變形成
url(r'^login/',views.view) # FBV和CBV在路由比對上是一緻的 都是url後面跟函數的記憶體位址
2.當浏覽器中輸入login會立刻觸發view函數的運作
def dispatch(self, request, *args, **kwargs):
'''
源碼部分
Try to dispatch to the right method; if a method doesn't exist,
defer to the error handler. Also defer to the error handler if the
request method isn't on the approved list.
'''
# 我們先以GET為例
if request.method.lower() in self.http_method_names: # 判斷目前請求方法是否在預設的八個方法内
# 反射擷取我們自己寫的類産生的對象的屬性或者方法
# 以GET為例
# handler = getattr(self,'get','取不到報錯的資訊')
# handler = get(request)
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs) # 直接調用我們自己的寫類裡面的get方法
# 源碼中先通過判斷請求方式是否符合預設的八個請求方法 然後通過反射擷取到自定義類中的對應的方法執行
Django settings源碼
前提:
- 1.django除了暴露給使用者一個settings.py配置檔案之外,自己内部還有一個全局的配置檔案
- 2.我們在使用配置檔案的時候 可以直接直接導入暴露給使用者的settings.py也可以使用django全局的配置檔案,并且後者居多
from django.conf import settings
- 3.django的啟動入口是manage.py
import os
import sys
if __name__ == "__main__":
# django在啟動的時候 就會往全局的大字典中設定一個鍵值對 值是暴露給使用者的配置檔案的路徑字元串
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day54.settings")
class Settings(object):
def __init__(self, settings_module): # settings_module = 'day54.settings'
# update this dict from global settings (but only for ALL_CAPS settings)
for setting in dir(global_settings): # django全局配置檔案
# dir擷取django全局配置檔案中所有的變量名
if setting.isupper(): # 判斷檔案中的變量名是否是大寫 如果是大寫才會執行/生效
setattr(self, setting, getattr(global_settings, setting)) # 給settings對象設定鍵值對
# store the settings module in case someone later cares
self.SETTINGS_MODULE = settings_module # 'day54.settings'
mod = importlib.import_module(self.SETTINGS_MODULE) # mod = 子產品settings(暴露給使用者的配置檔案)
for setting in dir(mod): # for循環擷取暴露給使用者的配置檔案中所有的變量名
if setting.isupper(): # 判斷變量名是否是大寫
setting_value = getattr(mod, setting) # 擷取大寫的變量名所對應的值
setattr(self, setting, setting_value) # 給settings對象設定鍵值對
"""
d = {}
d['username'] = 'jason'
d['username'] = 'egon'
使用者如果配置了就用使用者的
使用者如果沒有配置就用系統預設的
其實本質就是利用字典的鍵存在就是替換的原理 實作了使用者配置就用使用者的使用者沒配置就用預設的
"""
class LazySettings(LazyObject):
def _setup(self, name=None):
# os.environ你可以把它看成是一個全局的大字典
settings_module = os.environ.get(ENVIRONMENT_VARIABLE) # 從大字典中取值DJANGO_SETTINGS_MODULE所對應的值:day54.settings
# settings_module = 'day54.settings'
self._wrapped = Settings(settings_module) # Settings('day54.settings')
settings = LazySettings() # 單例模式
模闆層
模闆文法有兩大類:
- {{}} 變量相關
- {%%} 邏輯相關
過濾器:
- |
|length
|add
|default
|filesizeformat
|truncatewords
|truncatechars
|safe
|slice
前後端取消轉義:
前端:
- | safe
後端:
from django.utils.safestring import mark_safe
zzz = mark_safe('<h1>阿薩德搜啊第三款垃圾袋</h1>')
常用模闆文法:
- | safe
- | filesizeformat
- | date
标簽
{% for foo in user_list%}
{{ foo }}
{{ forloop }}
{% empty %}
# 當傳遞給我的循環對象是個空的情況下才會走empty下面的代碼塊
{% endfor %}
{% if flag %}
flag有值
{% elif tag %}
tag有值
{% else %}
兩個都沒值
{% endif %}
# 前端模闆文法for循環和if判斷也可以嵌套使用
{% with hobby.2.1.2.1.2.3.4.3 as h%}
{{ h }}
{{ hobby.2.1.2.1.2.3.4.3 }}
{% endwith %}
for循環裡面的forloop對象作用在字典上(if判斷也可以)
{% for foo in d.keys %}
<p>{{ foo }}</p>
{% endfor %}
{% for foo in d.values %}
<p>{{ foo }}</p>
{% endfor %}
{% for foo in d.items %}
<p>{{ foo }}</p>
{% endfor %}
自定義标簽與過濾器inclusion_tag
必備三步走戰略
- 1.在應用下建立一個名字必須叫做templatetags檔案夾
- 2.在建立的檔案夾下建立一個任意名的py檔案(my_tag.py)
- 3.在建立的py檔案中固定寫下面兩句話
from django import template
register = template.Library()
# 自定義過濾器
# 該過濾器隻做一個加法運算 是|add建議版本
@register.filter(name='baby')
def index(a,b):
return a+b
# 自定義标簽
# 支援傳多個值
@register.simple_tag(name='index')
def index(a,b,c,d):
return a+b+c+d
# 自定義inclusion_tag
"""
接收使用者傳入的參數 然後作用于一個html頁面
在該頁面上渲染資料 之後将渲染好的頁面
放到使用者調用inclusion_tag的地方
"""
@register.inclusion_tag('login.html',name='xxx')
def index(n):
# 産生login.html小頁面所需要的資料
return {"data":data}
html中如何使用自定義的過濾器,标簽,inclusion_tag
# 先加載
{% load my_tag %}
{{ num|baby:10 }}
{% index 1 2 3 4 %}
{% xxx 10 %}
模闆的繼承與導入
- 當多個頁面整體的樣式都大差不差的情況下 可以設定一個模闆檔案
- 在該模闆檔案中 使用block塊劃分多個預期
- 之後子版在使用模闆的時候 可以通過block塊的名字 來標明到底需要修改哪一部分區域
模闆一般情況下 應該至少有三個可以被修改的區域
{% block css %}
子頁面自己的css代碼
{% endblock %}
{% block content %}
子頁面自己的html代碼
{% endblock %}
{% block js %}
子頁面自己的js代碼
{% endblock %}
繼承模闆
# 模闆的繼承 使用方式
# 一般情況下 模闆上的block越多 頁面的可擴充性就越強
{% extends 'home.html' %}
{% block css %}
<style>
h1 {
color: red;
}
</style>
{% endblock %}
{% block content %}
<h1>登陸頁面</h1>
<form action="">
<p>username:<input type="text" class="form-control"></p>
<p>password:<input type="text" class="form-control"></p>
<input type="submit" class="btn btn-danger">
</form>
{% endblock %}
{% block js %}
{% endblock %}
模闆的導入
- 當你寫了一個特别好看的form表單/清單标簽等
- 可以将它當成一個子產品 哪個地方需要 就直接導入使用即可
{% include 'login.html' %}
PS:
- 一個模闆中通常block塊兒越多頁面的可擴充性越強
- 一般習慣性的取三塊内容(css,content,js)
模型層
單表操作
create_time = models.DateField()
關鍵性的參數
- 1.auto_now:每次操作資料 都會自動重新整理目前操作的時間
- 2.auto_now_add:在建立資料的時候 會自動将建立時間記錄下來 後續的修改不會影響該字段
注意:
- 在django中 你可以寫一個單獨測試某一個py檔案的測試腳本 不需要再頻繁的走web請求