引入三個表:用戶表,客戶表,校區表,班級表,梳理邏輯關係並遷移數據庫,生成表。javascript
使用admin插入數據,admin是Django提供的web形式的後臺數據管理頁面,它是和用戶認證組件相通的,使用超級用戶便可登陸admin後臺,並管理本身的數據庫。java
作出所有客戶列表頁面和個人客戶列表頁面。python
在python中,裝飾器以及前面講到的迭代器,生成器都是十二分重要的高級函數。要想理解裝飾器,首先要掌握如下幾點準備知識:web
在python的世界裏,函數和咱們以前的[1,2,3],'abc',8等同樣都是對象,並且函數是最高級的對象(對象是類的實例化,能夠調用相應的方法,函數是包含變量對象的對象)數據庫
def foo(): print('i am the foo') bar() def bar(): print('i am the bar') foo() # def bar(): # bar函數定義放到foo()後邊會報錯 # print('i am the bar')
帶着上面的問題,咱們看看函數在內存的存儲狀況,以下圖:django
既然函數是對象,那麼天然知足下面兩個條件:函數對象的調用僅僅比其餘對象多了一個()而已!foo,bar與a,b同樣都是個變量名。那麼上面示例的報錯問題也就解決了,由於只有函數加載到內存才能夠被調用。編程
1)函數能夠被賦給其餘變量緩存
def foo(): print('foo') bar=foo bar() foo() print(id(foo),id(bar)) #4321123592 4321123592
2)函數能夠被定義在另一個函數內(做爲參數&做爲返回值),相似於整型,字符串等對象閉包
#*******函數名做爲參數********** def foo(func): print('foo') func() def bar(): print('bar') foo(bar) #*******函數名做爲返回值********* def foo(): print('foo') return bar def bar(): print('bar') b=foo() b()
注意:這裏說的函數都是指函數名,好比foo;而foo()表示已經執行函數了,foo()是什麼類型取決於return的內容是什麼類型!!!另外,若是你理解不了對象,那麼就將函數理解成變量,由於函數對象總會由一個或多個變量引用,好比foo,bar。app
python容許建立嵌套函數,經過在函數內部def的關鍵字再聲明一個函數即爲嵌套。先看下面這個函數嵌套的示例,分析可否正常執行:
def foo(): print('foo') def bar(): print('bar') # bar() bar() # 報錯緣由:找不到這個引用變量 # 分析:沒錯,bar就是一個變量名,有本身的做用域的,所以bar()不能執行。
再看下面一個函數嵌套的示例,並思考執行inner函數的兩種方法有什麼區別:
def outer(): x = 1 def inner(): print (x) # inner() # 方式一 return inner # 方式二 # outer() # 方式一 in_func=outer() # 方式二:這裏其實就是一個變量賦值,將inner的引用對象賦值給in_func,相似於a=5,b=a同樣 in_func()
分析:兩種調用方式有區別嗎,不都是在外面調用inner嗎?按照方式二調用後,inner()已經加載到內存了!
回顧閉包的概念:若是在一個內部函數裏,對在外部做用域(但不是在全局做用域)的變量進行引用,那麼內部函數就被認爲是閉包(closure)。
如上示例,inner就是內部函數,inner裏引用了外部做用域的變量x(x在外部做用域outer裏面,不是全局做用域),則這個內部函數inner就是一個閉包。
說了這麼多,終於到裝飾器了。裝飾器本質上是一個函數,該函數用來處理其餘函數,它可讓其餘函數在不須要修改代碼的前提下增長額外的功能,裝飾器的返回值也是一個函數對象。它常常用於有切面需求的場景,好比:插入日誌、性能測試、事務處理、緩存、權限校驗等應用場景。裝飾器是解決這類問題的絕佳設計,有了裝飾器,咱們就能夠抽離出大量與函數功能自己無關的雷同代碼並繼續重用。歸納的講,裝飾器的做用就是爲已經存在的對象添加額外的功能。
好比,業務生產中有以下一個大量調用的函數:
def add(): for i in range(30000000): ret+=i print(ret) add()
如今有一個新的需求,但願能夠記錄下函數的執行時間,因而在函數中添加日誌代碼:
總結:雖然實現了需求,可是這樣作違反了開發的開放封閉原則的封閉原則,即不要輕易去改已經寫好方法!並且若是要給其餘函數也要加記錄時間的代碼,再用以上方法會形成代碼冗餘,因此想想有沒有其餘方法。你可能會想到單獨定義一個記錄時間的函數,以下:
import time def show_time(func): start_time=time.time() func() end_time=time.time() print('spend %s'%(end_time-start_time)) def add(): for i in range(30000000): ret+=i print(ret) show_time(add)
上面示例從邏輯上不難理解,並且運行正常。可是這樣的話,以前執行業務邏輯時,執行運行add(),可是如今不得不改爲show_time(add),這種方式就違反了開發的開放封閉原則的開放原則,即不要改動以前已有的調用方式。那麼有沒有更好的方式的呢?固然有,答案就是裝飾器。
若是,能夠將上例中的add()=show_time(add),那麼就能夠在不違反開放封閉原則前提下完成需求了,因此,咱們須要show_time(add)返回一個函數對象,而這個函數對象內則是核心業務函數:執行func()與裝飾函數時間計算,修改以下:
import time def show_time(func): def inner(): start_time=time.time() func() end_time=time.time() print('spend %s'%(end_time-start_time)) return inner def add(): for i in range(30000000): ret+=i print(ret) add=show_time(add) add()
分析:函數show_time就是裝飾器,它把真正的業務方法func包裹在函數裏面,看起來像add被上下時間函數裝飾了。在這個例子中,函數進入和退出時 ,被稱爲一個橫切面(Aspect),這種編程方式被稱爲面向切面的編程(Aspect-Oriented Programming)。
@符號是裝飾器的語法糖,在定義函數的時候使用,避免再一次賦值操做,以下示例:
import time def show_time(func): def inner(): start_time=time.time() func() end_time=time.time() print('spend %s'%(end_time-start_time)) return inner @show_time # add=show_time(add) def add(): for i in range(30000000): ret+=i print(ret) @show_time # bar=show_time(bar) def bar(): print('in the bar') time.sleep(2) add() bar()
如上所示,這樣咱們就能夠省去add = show_time(add)這一句了,直接調用add()便可獲得想要的結果。若是咱們有其餘的相似函數,咱們能夠繼續調用裝飾器來修飾函數,而不用重複修改函數或者增長新的封裝。這樣,咱們就提升了程序的可重複利用性,並增長了程序的可讀性。
這裏須要注意:add=show_time(add)實際上是把inner引用的對象引用給了add,而inner裏的變量func之因此能夠用,就是由於inner是一個閉包函數。
@show_time幫咱們作的事情就是當咱們執行業務邏輯foo()時,執行的代碼由粉框部分轉到藍框部分,僅此而已!裝飾器在Python使用如此方便都要歸因於Python的函數能像普通的對象同樣能做爲參數傳遞給其餘函數,能夠被賦值給其餘變量,能夠做爲返回值,能夠被定義在另一個函數內。
import time def show_time(func): def inner(a,b): start_time=time.time() func(a,b) end_time=time.time() print('spend %s'%(end_time-start_time)) return inner @show_time # add=show_time(add) def add(a,b): time.sleep(1) print(a+b) add(2,4)
import time def show_time(func): def inner(a,b): start_time=time.time() ret=func(a,b) end_time=time.time() print('spend %s'%(end_time-start_time)) return ret # 若被裝飾函數有返回值,則inner函數也必定要返回func(a,b)的結果 return inner @show_time # add=show_time(add) def add(a,b): time.sleep(1) return a+b print(add(2,5))
Django爲咱們提供了一個裝飾器函數login_required,當咱們只想限制少許頁面登陸才能訪問時,就可使用裝飾器函數,而沒有必要加中間件。
1)首先,在admin.py中配置以下信息:
from django.contrib import admin # Register your models here. from app01.models import * # 將models模塊中的全部類(表)引入 admin.site.register(UserInfo) # 括號中是model中的類(表),下面也如此 admin.site.register(Customer) admin.site.register(Campuses) admin.site.register(ClassList)
2)建立超級用戶
python manage.py createsuperuser
3)以超級用戶登陸admin後臺,開始錄入數據
方式一:
pip3 install multiselectfield
方式二:pycharm軟件上按以下操做
file -> settints -> Project:xxx -> Project Interpreter -> 右側綠色加號 -> 搜索multiselectfield ->Install Package
解釋:咱們以前學過gender=models.CharField(choices=(('male','男')('female','女'))),使用modelform會渲染成多個type爲radio的input標籤,model中定義course = MultiSelectField("諮詢課程", choices=(('Linux', 'Linux中高級'),('PythonFullStack', 'Python高級全棧開發'),), blank=True, null=True),使用modelform會渲染成多個type爲checkbox的input標籤。
qq_name = models.CharField('QQ暱稱', max_length=64, blank=True, null=True)
解釋:null=True表示數據庫中不能爲空,blank=True表示使用modelform組件中校驗該字段輸入時不能爲空,而只寫null=True則不能校驗。Django的admin也是基於modelform實現的,因此使用admin提交表單數據時,只寫了null=True而沒有寫blank=True的則必須輸入值,不能爲空。
search 屬性是一個可讀可寫的字符串,可設置或返回當前 URL 的查詢部分(即問號 ? 以後的部分)。
語法:string.slice(start,end)
解釋:提取字符串的某個部分,並以新的字符串返回被提取的部分,索引從0開始,顧頭不顧尾。