Django--路由層、視圖層、模版層

  

路由層:

  路由匹配

    url(正則表達式,視圖函數內存地址)

    只要正則匹配到了內容,就不再往下匹配,而是直接運行後面的視圖函數

      匹配首頁)

        url(r'^&', home)

      匹配尾頁

        url(r'', errors)

 

    路由匹配的規律

      第一次是按照用戶輸入什麼就匹配什麼

      第二次是Django會讓瀏覽器自動在尾部加上斜槓再次匹配,要是還是匹配不上就不報錯

    上述的規律不是瀏覽器的特點,而是Django的功能

      Django settings文件夾中

      APPEND_SALSH = True  # 這個是自動加斜槓的

 

  無名分組

    路由匹配成功之後,如果正則表達式中有分組,那麼在調用視圖函數的時候會將括號內正則表達式匹配到的內容當作位置參數傳遞給後面的視圖函數

      url(r'^index/(\d+)/', index)

 

      def index(request, args):
        return Httpresponse對象

 

  有名分組

    路由匹配成功之後,如果正則表達式中有有名分組並且起了別名的話,那麼在調用視圖函數的時候會將括號內正則表達式匹配到的內容當作關鍵字參數傳遞給後面的視圖函數

      url(r'^index/(?P<year>\d+)/', index)

 

      def index(request, index):
        return Httpresponse對象

  有名分組和無名分組不能混合使用,但是兩者可以單獨使用多個

  

  反向解析

    由來是很多html頁面和後端代碼中頻繁使用了指名道姓的url(/index/)

    那麼這個時候如果一旦發生了變化,前後端所有的地方都需要修改,造成了可維護性比較差

    反向解析的本質就是通過某個方法獲取的一個能夠訪問對應的url的結果

  

    沒有涉及到正則表達式符號的情況下

      url(r'^index/', index, name='index')

      前端:

        {% url 'aaa' %}

      後端:

        from django.shortcuts import HttpResponse,render,redirect,reverse
        url = reverse('index')

    無名分組和有名分組的情況

      無名:

        url(r'^index/(\d+)/',index,name='bbb')

        前端:

          {% url 'bbb' 1 %}

        後端:

          url = reverse('aaa',args=(1,))

      有名:

        url(r'^index/(?P<edit_id>\d+)/',index,name='bbb')

        前端:

          {% url 'bbb' 1 %}
          {% url 'bbb' year=1 %}

        後端:    

          url = reverse('aaa',args=(1,))
          url = reverse('aaa',kwargs={'year':1})

 

  路由分發

    include()

      django中的每一個app都可以是獨立的urls.py, static靜態文件, templates模版文件夾

      真是基於上面的特點,Django就可以很好的支持多人分組開發,每個人只需要開發各自的app就可以了,最後只需要創建一個空的Django項目將所有人的app註冊進來,總路由中來一個路由分發就可以將多個人的功能整合到一個項目中了

      當項目比較巨大的時候,如果不使用路由分發,那麼路由中的url代碼太多了,不利於維護和更新

        from app01 import urls as app01_urls
        from app02 import urls as app02_urls
        url(r'應用名前綴/',include(app01_urls))
        url(r'應用名前綴/',include(app02_urls))

        # 推薦使用下面的方式
        url(r'應用名前綴/',include('app01.urls'))
        url(r'應用名前綴/',include('app02.urls'))

      路由分發要注意的點:

        總路由中的最後千萬不要加$符號

  名稱空間

    你在起別名的時候,雖然能夠同一個應用下不重名,但是你沒辦法實現多個人多個app不重名的情況

    一旦重名在進行反向解析的話就不能識別所在的應用了

    在總路由中 給每一個應用開設一個名稱空間

      url(r'應用名前綴/',include('app01.urls',namespace='app01'))
      url(r'應用名前綴/',include('app02.urls',namespace='app02'))

    子路由:  

      url(r'^index/',index,name='aaa')
      url(r'^index/',index,name='aaa')

    反向解析的時候:    

      reverse('app01:aaa')
      reverse('app02:aaa')
      {% url 'app01:aaa' %}
      {% url 'app02:aaa' %}

    其實你可以完全不使用名稱空間 只需要保證別名不重複就行,也就是你在起別名的時候給每個別名加上所在應用名的前綴

 

  僞靜態  

    就是在url後面加上一個.html

 

  虛擬環境

    不同的項目應該有屬於該項目獨有的python解釋器環境,這樣的話就可以避免資源的浪費以及版本兼容的問題

    注意⚠️:

      虛擬環境雖然好用,但是不要無限制的進行創建 你機器上的虛擬環境可以手動進行刪除

  Django版本之間的區別:

    路由2.X裏面的是path第一個參數也不再支持正則表達式,而是寫什麼就匹配什麼,如果這個時候你還是想要使用正則進行匹配的話,這裏面提供了一個re_path模塊就是1.X裏面的url

    雖然path不再支持正則,但是他提供了五種轉化器(可以將路由匹配到的內容自動轉換成對應的數據格式然後再傳遞給後面的視圖函數)      

 

 

視圖層

  如果一個一個應用下面的視圖函數特別多,這時候你就可以新建一個views文件夾,然後根據不同的功能起不同的名字的py文件存放不同的功能,實現持續的解耦合 和增加可讀性

  views

    user.py

    account.py

    order.py

    ...  

  

  前後端分離

    JsonResponse(data,safe=False,json_dumps_params={'ensure_ascii':False})

    如果在son_dumps_params裏面你傳遞的不是字典數據,那麼需要手動指定safe=False

 

  form表單上傳文件

    需要注意的事項:

      1、method必須是post

      2、enctype必須要制定成formdata

      3、目前需要考慮的 需要將settings配置文件中的csrf中間件註釋掉

    後端不再通過request.POST獲取文件數據,而是通過request.FILES

      file_obj = request.FILES.get('myfile')
      file_obj.name # 文件名
      with open(file_obj.name,'wb') as f:
        for chunk in file_obj.chunks():
        f.write(chunk)

 

  request

    request.method

    request.GET
    request.POST

    request.FILES

    request.body  # 獲得是原生的二進制的數據

    request.path  # 只拿url

    request.get_full_path()  # url+?後面的參數

    

 

 

  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)
        print(res)
        return HttpResponse(res)

 

  FBV和CBV

    視圖函數並不是指函數 同樣也可以指類

      FBV:基於函數的視圖(面向函數式編程)

      CBV:基於類的視圖 (面向對象式編程)

            # 問題:基於CBV的視圖函數 
                    """get請求來就會走類裏面get方法,post請求來就會走類裏面post方法 爲什麼???"""
                    
                    urls.py中
                        url(r'^login/',views.MyLogin.as_view())  # 由於函數名加括號的執行優先級最高,所以這一句話寫完就會立刻執行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對象設置鍵值對
                            # 給settings對象設置鍵值對  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()  # 單例模式    
                

 

 

 

 模版層

  模版語法

    {{}}變量相關

    {%%}邏輯相關

    都是爲模版來傳值的

  過濾器:|

  前後端取消轉義

    前端:

      |safe

    後端: 

      from django.utils.safestring import mark_safe
      zzz = mark_safe('<h1>阿薩德搜啊第三款垃圾袋</h1>')

    |safe

    |filesizeformat

    |date

  標籤{%%}

    

            {#{% for foo in l %}#}
                    {#    <p>{{ forloop }}</p>#}
                    {#{% endfor %}#}
                    {##}
                    {##}
                    {#{% if '' %}#}
                    {#<p>xxx條件爲true</p>#}
                    {#    {% else %}#}
                    {#    <p>xxx條件爲false</p>#}
                    {#{% endif %}#}

                    {##}
                    {#{% for foo in '' %}#}
                    {#    {% if forloop.first %}#}
                    {#        <p>這是我的第一次</p>#}
                    {#        {% elif forloop.last %}#}
                    {#        <p>這是最後一次了啊</p>#}
                    {#        {% else %}#}
                    {#        <p>來啊來啊!!!</p>#}
                    {#    {% endif %}#}
                    {#    {% empty %}#}
                    {#    <p>當for循環的對象爲空的時候 會走empty</p>#}
                    {#{% endfor %}#}

                    {##}
                    {#<p>#}
                    {#    django模板語法在取值的時候 統一使用句點符(大白話就是 點號   .)#}
                    {#    {% with l.6.3.name as ttt %}  可以給一個比較複雜的取值操作取一個別名 之後在with語句中 就可以使用該別名#}
                    {#        {{ ttt }}#}
                    {#        {{ l.6.3.name }}#}
                    {#    {% endwith %}#}
                    {#</p>#}


                    {% 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 %}

 

 

     for循環裏面的forloop對象

    if判斷

 

 

  自定義標籤、過濾器、inclusion_tag

    自定義固定的三步走戰略:

      1、必須在你的應用下新建一個叫templatetags文件夾

      2、在該文件夾內新建一個任意名稱的py文件

      3、在該py文件中固定先寫入下面兩句代碼

        from django import template
        register = template.Library()

 

    自定義過濾器

            @register.filter(name='baby')
                    def index(a,b):
                        # 該過濾器只做一個加法運算  是|add建議版本
                        """
                        |length
                        |add
                        |default
                        |filesizeformat
                        |truncatewords
                        |truncatechars
                        |safe
                        |slice

                        :param a:
                        :param b:
                        :return:
                        """
                        print('下午剛起牀 一臉懵逼')
                        return a + b

 

 

 

     自定義標籤,支持傳多個值

    

            @register.simple_tag(name='jason')
                    def xxx(a,b,c,year):
                        return '%s?%s|%s{%s'%(a,b,c,year)

 

 

 

     自定義inclusion_tag  

      接受用戶傳入的參數  然後作用於一個html頁面,在該頁面上渲染數據,之後將渲染好的頁面放到用戶調用inclusion_tag的地方

      

            @register.inclusion_tag('bigplus.html')
                    def bigplus(n):
                        l = []
                        for i in range(n):
                            l.append('第%s項'%i)
                        return {'l':l}

 

 

 

   模版的繼承

    在多個頁面整體樣式都差不多的情況下,這時候就可以設置一個模版文件了,在該模版文件中,使用block劃分多個區域,之後子版本在使用模版的時候 可以通過block塊的名字來選定到底需要修改哪一部分區域

    模版一般情況下 都應該至少有三個可以被修改的地方

      1、子頁面自己的css代碼

      2、子頁面自己的html代碼

      3、子頁面自己的js代碼

 

    一般情況下 模版上的block越多,頁面的可擴展性就越強

    

  模版的導入

          {% include 'beautiful.html' %}
            
            
                當你寫了一個特別好看的form表單/列表標籤等
                可以將它當成一個模塊 哪個地方需要 就直接導入使用即可

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章