Django框架詳解

1、WSGI接口

WSGI服務網關接口:Web Server Gateway Interface縮寫。html

WSGI是python定義的Web服務器和Web應用程序之間或框架之間的通用接口標準。前端

WSGI定義:Web開發者實現了一個函數,並響應HTTP請求。python

WSGI將Web組件分紅三類:Web服務器(WSGI Server),Web中間件(WSGI Middleware),Web用用程序(WSGI Application).正則表達式

Web服務器接收HTTP請求,調用WSGI接口標準註冊的WSGI Application,最後將響應返回給客戶端。數據庫

Web應用的本質:1.瀏覽器發送HTTP請求。django

                            2.服務器接收請求,生成HTML頁面。瀏覽器

                            3.服務器將HTML頁面當成HTTP響應的body發送給瀏覽器。安全

                            4.瀏覽器接收到HTTP響應,並從HTTP Body中HTML並渲染出來服務器

2、中間件

django的中間件(Middleware),其實就是一個類,在請求前和請求後,django會根據本身的規則並在合適的時機執行中間件中相應的方法。app

中間件的官方說法是中間件是一個用來處理django的請求和相應的框架級別的鉤子。在全局範圍內改變django的輸入和輸出,每一箇中間件都有特定的功能。

中間件能夠定義五個方法:1.process_request(self, request)

                                          2.process_response(self, request, response)

                                          3.process_view(self, request, view_func, view_args, view_kwargs)

                                          4.process_exception(self, request, exception)

                                          5.process_template_response(self, request, response)

以上方法返回的能夠是None也能夠是HttpResponse對象,若是是None,這繼續按照django的規則繼續執行下面的中間件,若是是HttpResponse對象,則直接把對象返回給用戶。

process_request

process_request有一個參數,就是request,這個request和視圖函數中的request是同樣的。它的返回值能夠是None也能夠是HttpResponse對象。返回值是None的話,按正常流程繼續走,交給下一個中間件處理,若是是HttpResponse對象,Django將不執行視圖函數,而是直接走本中間件的process_response方法,倒序返回,將相應對象返回給瀏覽器。

  1. 中間件的process_request方法是在執行視圖函數以前執行的。
  2. 當配置多箇中間件時,會按照MIDDLEWARE中的註冊順序,也就是列表的索引值,從前到後依次執行的。
  3. 不一樣中間件之間傳遞的request都是同一個對象

process_response

process_response有兩個參數,一個是request,一個是response。這裏面的request和process_request裏面的參數request是同樣的對象,response是視圖函數返給回給用戶的是Httpresponse對象,而且該方法返回值必須是HttpResponse對象。

  1. 中間件的process_response方法是在執行視圖函數以後執行的。
  2. 當配置多箇中間件時,會按照MIddleware註冊順序的倒序執行,從後往前執行。

process_view

process_view有四個參數:1.request是HttpResponse對象

             2.view_func是django即將用到的視圖函數,它是實際的視圖函數

                                           3.view_args是傳遞給視圖函數的位置參數的列表

                                           4.view_kwargs是傳遞給視圖函數的關鍵之參數的字典

                                           5.args和kwargs都不包含第一個參數request

  1. 中間件的process_view方法是在執行視圖函數以前執行的。
  2. process_view方法是在全部的process_request方法執行完以後執行的
  3. 當配置多箇中間件時,會按照Middleware的註冊順序從前日後執行

process_view它應該返回一個None或HttpResponse對象,若是返回None,則繼續執行剩下的中間件的process_view方法,而後再執行相應的視圖。若是返回HttpResponse對象,則再也不執行剩下的process_view和後面的視圖函數,它將執行中間件的process_response方法並將應用到HttpResponse並返回結果。

process_exception

process_exception有兩個參數:request是一個HttpResponse對象,exception是視圖產生的Exception對象。這個方法是隻有視圖函數執行異常時才執行的,它返回的對象能夠是一個None也能夠是一個HttpResponse對象。若是是HttpResponse對象,django將調用模板和process_response方法並返回給瀏覽器。,不然默認處理異常。

  1. 若是視圖函數中無異常,process_exception方法則不執行。
  2. 當配置多箇中間件時,會按照Middleware的註冊順序從後往前執行
  3. 當一箇中間的process_exception方法執行了,則直接調用process_response方法,再也不執行其餘中間件的process_exception方法

process_template_response

它有兩個參數,request參數是HttpResponse對象,response參數是TemplateResponse對象(由視圖函數或中間件產生)。

  1. process_template_response方法是在視圖函數以後當即執行
  2. 可是它由一個前提條件,就是視圖函數返回的對象有一個render()(或則代表代表該對象是一個TemplateResponse對象或等價方法)
  3. 當配置多箇中間件時,會按照Middleware的註冊順序從後往前執行
  4. 而後執行視圖函數返回的HttpResponse對戲那個的render()方法,並返回一個新的HttpResponse對象
  5. 而後執行process_response方法

 3、URL路由系統(URLconf)

URL配置(URLconf)就像django所支撐網站的目錄,它的本質就是該URL和要爲該URL調用的視圖函數之間的映射表。

# 基本配置
from djago.conf.urls import url

urlpattrens = [
url(正則表達式,views視圖函數名,參數,別名),
]
# 注意事項
1.從上到下一次匹配,一旦匹配成功就再也不匹配
2.不須要添加一個前導的斜槓,由於每一個URL都有
3.每一個正則表達式前的r是可選的,但建議加上
# 補充說明
APPEEND_SLASH = True # django默認爲True,做用就是自動在網址末尾加/
  1. URLconf不檢驗請求方法,同一個URL不論什麼請求方式,都走同一個視圖函數。
  2. 捕捉到的參數永遠都是字符串
# 起別名
url(r'^home', views.home, name='home'),  # 給個人url匹配模式起名爲 home
url(r'^index/(\d*)', views.index, name='index'),  # 給個人url匹配模式起名爲index

這樣:

在模板裏面能夠這樣引用:

{% url 'home' %}

在views函數中能夠這樣引用:

from django.urls import reverse

reverse("index", args=("2018", ))

命名空間模式

即便不一樣的APP使用相同的URL名稱,URL的命名空間模式也可讓你惟一反轉命名的URL。

舉個例子:

project中的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')),
]

app01中的urls.py

from django.conf.urls import url
from app01 import views
 
app_name = 'app01'
urlpatterns = [
    url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
]

app02中的urls.py

from django.conf.urls import url
from app02 import views
 
app_name = 'app02'
urlpatterns = [
    url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
]

如今,個人兩個app中 url名稱重複了,我反轉URL的時候就能夠經過命名空間的名稱獲得我當前的URL。

語法:

'命名空間名稱:URL名稱'

模板中使用:

{% url 'app01:detail' pk=12 pp=99 %}

views中的函數中使用

v = reverse('app01:detail', kwargs={'pk':11})

 這樣即便app中URL的命名相同,我也能夠反轉獲得正確的URL了。

 有名分組

# 這種形式是無名分組
from
django.conf.urls import url from . import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/([0-9]{4})/$', views.year_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), ]

沒有命名的正則表達式組(經過圓括號)來捕獲URL中的值並以位置參數傳遞給視圖。在更高級的用法中,可使用命名的正則表達式組來捕獲URL 中的值並以關鍵字 參數傳遞給視圖。

在Python 正則表達式中,命名正則表達式組的語法是(?P<name>pattern),其中name 是組的名稱,pattern 是要匹配的模式。

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]

這個實現與無名分組徹底相同,只有一個細微的差異:捕獲的值做爲關鍵字參數而不是位置參數傳遞給視圖函數。例如:

/articles/2005/03/    
請求將調用views.month_archive(request, year='2005', month='03')函數
/articles/2003/03/03/ 
請求將調用函數views.article_detail(request, year='2003', month='03', day='03')。

4、Template模板

 python的模板:HTML代碼+邏輯控制代碼

# 變量  用雙大括號來引用變量  用法:{{ title }}
# 邏輯  用大括號和百分號組合  用法:{% for user in user_list %}  {% endfor %}
# 點 .  在模板裏面有特殊的含義,就是獲取對象的相應屬性值  {{ user.name }}
# 模板中支持的寫法
{# 取l中的第一個參數 #} {{ l.0 }} {# 取字典中key的值 #} {{ d.name }} {# 取對象的name屬性 #} {{ person_list.0.name }} {# .操做只能調用不帶參數的方法 #} {{ person_list.0.dream }}

 Filters過濾器的使用

語法: {{ value|filter_name:參數 }}  
{{ value|default:"nothing" }}
{{ value|length }} # 返回value的長度
{{ value|filesizeformat }} # 將十進制數轉爲爲KB,MB,GB等
{{ value|slice:"2:-1" }} # 切片
{{ value|data:"Y-m-d H:i:s" }} # 格式化時間
{{ value|safa }} # 告訴django這段代碼是安全的,沒必要轉譯
{{ value|truncatechars:9 }} # 截斷,若是value的字符數大於9,則只顯示前9個字符,後面的用...表示。
{{ value|upper }} # 將value的字母全變成大寫
{{ value|add:2 }} # value值+2並顯示
{{ value|cut:"a" }} # 移除指定字符

自定義filter過濾器

from django import template
register = template.Library()

@register.filter(name="cut")
def cut(value, args):
return value.replace(args, "")

@register.filter(name="add")
def add(value):
return "{}很可愛!".format(value)
{# 先導入咱們自定義filter那個文件 #}
{% load app01_filters %}

{# 使用咱們自定義的filter #}
{{ somevariable|cut:"0" }}
{{ value|add }}

注意:以上代碼要在django項目中使用

前端未完待續......

5、Views視圖

 django的兩種處理請求的方式:FBV和CBV

FBV:function base views  在視圖裏面基於函數處理請求

CBV:class base views  在視圖裏面基於類處理請求

# urls.py中
url(r'^add_class/$', views.AddClass.as_view()),

Response對象

HttpResponse類位於django.http模塊中。

使用

傳遞字符串

from django.http import HttpResponse
response = HttpResponse("Here's the text of the Web page.")
response = HttpResponse("Text only, please.", content_type="text/plain")

設置或刪除響應頭信息

response = HttpResponse()
response['Content-Type'] = 'text/html; charset=UTF-8'
del response['Content-Type']

屬性

HttpResponse.content:響應內容

HttpResponse.charset:響應內容的編碼

HttpResponse.status_code:響應的狀態碼

JsonResponse對象

JsonResponse是HttpResponse的子類,專門用來生成JSON編碼的響應。

from django.http import JsonResponse

response = JsonResponse({'foo': 'bar'})
print(response.content)

b'{"foo": "bar"}'

默認只能傳遞字典類型,若是要傳遞非字典類型須要設置一下safe關鍵字參數。

response = JsonResponse([1, 2, 3], safe=False)

render()

結合一個給定的模板和一個給定的上下文字典,並返回一個渲染後的 HttpResponse 對象。

from django.shortcuts import render

def my_view(request):
    # 視圖的代碼寫在這裏
    return render(request, 'myapp/index.html', {'foo': 'bar'})

redirect()

參數能夠是:

  • 一個模型:將調用模型的get_absolute_url() 函數
  • 一個視圖,能夠帶有參數:將使用urlresolvers.reverse 來反向解析名稱
  • 一個絕對的或相對的URL,將原封不動的做爲重定向的位置。

默認返回一個臨時的重定向;傳遞permanent=True 能夠返回一個永久的重定向。

示例:

你能夠用多種方式使用redirect() 函數。

傳遞一個具體的ORM對象(瞭解便可)

將調用具體ORM對象的get_absolute_url() 方法來獲取重定向的URL:

from django.shortcuts import redirect
 
def my_view(request):
    ...
    object = MyModel.objects.get(...)
    return redirect(object)

傳遞一個視圖的名稱

def my_view(request):
    ...
    return redirect('some-view-name', foo='bar')

傳遞要重定向到的一個具體的網址

def my_view(request):
    ...
    return redirect('/some/url/')

固然也能夠是一個完整的網址

def my_view(request):
    ...
    return redirect('http://example.com/')

默認狀況下,redirect() 返回一個臨時重定向。以上全部的形式都接收一個permanent 參數;若是設置爲True,將返回一個永久的重定向:

def my_view(request):
    ...
    object = MyModel.objects.get(...)
    return redirect(object, permanent=True)  

擴展閱讀: 

臨時重定向(響應狀態碼:302)和永久重定向(響應狀態碼:301)對普通用戶來講是沒什麼區別的,它主要面向的是搜索引擎的機器人。

A頁面臨時重定向到B頁面,那搜索引擎收錄的就是A頁面。

A頁面永久重定向到B頁面,那搜索引擎收錄的就是B頁面。

6.二、操做表

基本操做

#
    #
    # models.Tb1.objects.create(c1='xx', c2='oo')  增長一條數據,能夠接受字典類型數據 **kwargs

    # obj = models.Tb1(c1='xx', c2='oo')
    # obj.save()

    #
    #
    # models.Tb1.objects.get(id=123)         # 獲取單條數據,不存在則報錯(不建議)
    # models.Tb1.objects.all()               # 獲取所有
    # models.Tb1.objects.filter(name='seven') # 獲取指定條件的數據

    #
    #
    # models.Tb1.objects.filter(name='seven').delete() # 刪除指定條件的數據

    #
    # models.Tb1.objects.filter(name='seven').update(gender='0')  # 將指定條件的數據更新,均支持 **kwargs
    # obj = models.Tb1.objects.get(id=1)
    # obj.c1 = '111'
    # obj.save()                                                 # 修改單條數據
    # save是更改全部字段,即便更改一個字段,也會將全部字段從新賦值, 不推薦
    # update更改,只更改修改的字段,推薦使用

    # update方式修改不能用get的緣由是:update是QuerySet對象的方法,get返回的是一個model對象,它沒有update方法,而filter返回的是一個QuerySet對象(filter裏面的條件可能有多個條件符合,好比name='alvin',可能有兩個name='alvin'的行數據)

基本操做
基本操做

查詢相關API

# 查詢相關API:

#  <1>filter(**kwargs):      它包含了與所給篩選條件相匹配的對象

#  <2>all():                 查詢全部結果

#  <3>get(**kwargs):         返回與所給篩選條件相匹配的對象,返回結果有且只有一個,若是符合篩選條件的對象超過一個或者沒有都會拋出錯誤。

#-----------下面的方法都是對查詢的結果再進行處理:好比 objects.filter.values()--------

#  <4>values(*field):        返回一個ValueQuerySet——一個特殊的QuerySet,運行後獲得的並非一系列 model的實例化對象,而是一個可迭代的字典序列
                                     
#  <5>exclude(**kwargs):     它包含了與所給篩選條件不匹配的對象

#  <6>order_by(*field):      對查詢結果排序

#  <7>reverse():             對查詢結果反向排序

#  <8>distinct():            從返回結果中剔除重複紀錄

#  <9>values_list(*field):   它與values()很是類似,它返回的是一個元組序列,values返回的是一個字典序列

#  <10>count():              返回數據庫中匹配查詢(QuerySet)的對象數量。

#  <11>first():               返回第一條記錄

#  <12>last():                返回最後一條記錄

#  <13>exists():             若是QuerySet包含數據,就返回True,不然返回False

查詢相關API
查詢API

進階操做(了不得的雙下劃線)

# 獲取個數
        #
        # models.Tb1.objects.filter(name='seven').count()

        # 大於,小於
        #
        # models.Tb1.objects.filter(id__gt=1)              # 獲取id大於1的值
        # models.Tb1.objects.filter(id__gte=1)              # 獲取id大於等於1的值
        # models.Tb1.objects.filter(id__lt=10)             # 獲取id小於10的值
        # models.Tb1.objects.filter(id__lte=10)             # 獲取id小於10的值
        # models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 獲取id大於1 且 小於10的值

        # in
        #
        # models.Tb1.objects.filter(id__in=[11, 22, 33])   # 獲取id等於十一、2二、33的數據
        # models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in

        # isnull
        # Entry.objects.filter(pub_date__isnull=True)

        # contains
        #
        # models.Tb1.objects.filter(name__contains="ven")
        # models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感
        # models.Tb1.objects.exclude(name__icontains="ven")

        # range
        #
        # models.Tb1.objects.filter(id__range=[1, 2])   # 範圍bettwen and

        # 其餘相似
        #
        # startswith,istartswith, endswith, iendswith,

        # order by
        #
        # models.Tb1.objects.filter(name='seven').order_by('id')    # asc
        # models.Tb1.objects.filter(name='seven').order_by('-id')   # desc

        # group by
        #
        # from django.db.models import Count, Min, Max, Sum
        # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
        # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"

        # limit 、offset
        #
        # models.Tb1.objects.all()[10:20]

        # regex正則匹配,iregex 不區分大小寫
        #
        # Entry.objects.get(title__regex=r'^(An?|The) +')
        # Entry.objects.get(title__iregex=r'^(an?|the) +')

        # date
        #
        # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
        # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))

        # year
        #
        # Entry.objects.filter(pub_date__year=2005)
        # Entry.objects.filter(pub_date__year__gte=2005)

        # month
        #
        # Entry.objects.filter(pub_date__month=12)
        # Entry.objects.filter(pub_date__month__gte=6)

        # day
        #
        # Entry.objects.filter(pub_date__day=3)
        # Entry.objects.filter(pub_date__day__gte=3)

        # week_day
        #
        # Entry.objects.filter(pub_date__week_day=2)
        # Entry.objects.filter(pub_date__week_day__gte=2)

        # hour
        #
        # Event.objects.filter(timestamp__hour=23)
        # Event.objects.filter(time__hour=5)
        # Event.objects.filter(timestamp__hour__gte=12)

        # minute
        #
        # Event.objects.filter(timestamp__minute=29)
        # Event.objects.filter(time__minute=46)
        # Event.objects.filter(timestamp__minute__gte=29)

        # second
        #
        # Event.objects.filter(timestamp__second=31)
        # Event.objects.filter(time__second=2)
        # Event.objects.filter(timestamp__second__gte=31)

進階操做
雙下方法

連表操做(了不得的雙下劃線)

利用雙下劃線和 _set 將表之間的操做鏈接起來

class UserProfile(models.Model):
    user_info = models.OneToOneField('UserInfo')
    username = models.CharField(max_length=64)
    password = models.CharField(max_length=64)

    def __unicode__(self):
        return self.username


class UserInfo(models.Model):
    user_type_choice = (
        (0, u'普通用戶'),
        (1, u'高級用戶'),
    )
    user_type = models.IntegerField(choices=user_type_choice)
    name = models.CharField(max_length=32)
    email = models.CharField(max_length=32)
    address = models.CharField(max_length=128)

    def __unicode__(self):
        return self.name


class UserGroup(models.Model):

    caption = models.CharField(max_length=64)

    user_info = models.ManyToManyField('UserInfo')

    def __unicode__(self):
        return self.caption


class Host(models.Model):
    hostname = models.CharField(max_length=64)
    ip = models.GenericIPAddressField()
    user_group = models.ForeignKey('UserGroup')

    def __unicode__(self):
        return self.hostname

表結構實例
表結構
user_info_obj = models.UserInfo.objects.filter(id=1).first()
print(user_info_obj.user_type)
print(user_info_obj.get_user_type_display())
print(user_info_obj.userprofile.password)
 
user_info_obj = models.UserInfo.objects.filter(id=1).values('email', 'userprofile__username').first()
print(user_info_obj.keys())
print(user_info_obj.values())
OneToOne
相關文章
相關標籤/搜索