天天看點

render内部原理/FBV與CBV/Django settings源碼(重要)/模闆層/模型層/自定義标簽與過濾器inclusion_tag/模闆的繼承與導入基礎要點Django settings源碼模闆層标簽自定義标簽與過濾器inclusion_tag模闆的繼承與導入模型層

基礎要點

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請求