Django web框架學習之旅(4)

《Django Web 框架》

目錄


  • Django Shell使用

    • 在Django提供了一個交互式的操作項目叫Django Shell 它能夠在交互模式用項目工程的代碼執行相應的操作

    • 利用Django Shell 可以代替編寫View的代碼來進行直接操作

    • 在Django Shell 下只能進行簡單的操作,不能運行遠程調式

    • 啓動 Django shell 顯示IPython風格的交互界面如下:

      $ python3 manage.py shell
      manage.py shell
      Python 3.6.1 (v3.6.1:69c0db5050, Nov 11 2019, 01:21:04) 
      Type 'copyright', 'credits' or 'license' for more information
      IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.
      
      In [1]: 
      In [2]: from bookstore import models
      In [3]: models.Book.objects.create(title="Python")
      Out[3]: <Book: Book object>
      In [4]: book = models.Book.objects.create(title='C++')
      In [4]: print(book)
      Book object
      

  • admin 後臺數據庫管理

    • django 提供了比較完善的後臺管理數據庫的接口,可供開發過程中調用和測試使用

    • django 會蒐集所有已註冊的模型類,爲這些模型類提拱數據管理界面,供開發者使用

    • 使用步驟:

      • 1、創建後臺管理賬號

        後臺管理--創建管理員帳號
        python3 manage.py createsuperuser
        
        $ python3 manage.py createsuperuser
        Username (leave blank to use 'tarena'): dayin  # 此處輸入用戶名
        Email address: [email protected]  # 此處輸入郵箱
        Password: # 此處輸入密碼(密碼要複雜些,否則會提示密碼太簡單)
        Password (again): # 再次輸入重複密碼
        Superuser created successfully.
        $ 
        
      • 2、用註冊的賬號登錄後臺管理界面

        • 後臺管理界面地址: http://127.0.0.1:8000/admin
    • 自定義後臺管理數據表

      • 若要自己定義的模型類也能在 /admin 後臺管理界中顯示和管理,需要將自己的類註冊到後臺管理界面

      • 添加自己定義模型類的後臺管理數據表的,需要用admin.site.register(自定義模型類) 方法進行註冊

      • 配置步驟如下:

        1. 在應用app中的admin.py中導入註冊要管理的模型models類, 如:  from . import models
        2. 調用 admin.site.register 方法進行註冊,如: 
                                     			  from django.contrib import admin
        							 			  admin.site.register(自定義模型類)
        3. 示例:
        如: 在 bookstore/admin.py 添加如下代碼對Book類進行管理
        
        # file: bookstore/admin.py
        from django.contrib import admin
        # Register your models here.
        
        from . import models
        ...
        admin.site.register(models.Book)  # 將Book類註冊爲可管理頁面
        							 			
        
    • 修改後臺Models的展現形式

      • 在admin後臺管理數據庫中對自定義的數據記錄都展示爲 XXXX object 類型的記錄,不便於閱讀和判斷

      • 在用戶自定義的模型類中可以重寫 def str(self): 方法解決顯示問題,如:

        classd Bookstore(models.Model):
            ...
            def __str__(self):
                return "書名" + self.title
        
    • 模型管理器類

      • 作用:

         用後臺管理界面添加便於操作的新功能。
        
      • 說明:

          後臺管理器類須繼承自 django.contrib.admin 裏的 ModelAdmin 類
        
      • 模型管理器使用方法:

        1. 在 <應用app>/admin.py 裏定義模型管理器類
        
        	class XXXX_Manager(admin.ModelAdmin):
        	    ......
        
        2. 註冊管理器與模型類關聯
        
        		from django.contrib import admin
        		from . import models
        		# 註冊models.YYYY 模型類與 管理器類 XXXX_Manager 關聯
        		admin.site.register(models.YYYY, XXXX_Manager) 
        3. 示例:
        
        		# file : bookstore/admin.py
        		from django.contrib import admin
        		from . import models
        		
        		class BookAdmin(admin.ModelAdmin):
        		    list_display = ['id', 'title', 'price', 'market_price']
        		
        		admin.site.register(models.Book, BookAdmin)
        
        
      • 模型管理器類ModelAdmin中實現的高級管理功能

        1. list_display 去控制哪些字段會顯示在Admin 的修改列表頁面中。
        2. list_display_links 可以控制list_display中的字段是否應該鏈接到對象的“更改”頁面。
        3. list_filter 設置激活激活Admin 修改列表頁面右側欄中的過濾器
        4. search_fields 設置啓用Admin 更改列表頁面上的搜索框。 
        5. list_editable 設置爲模型上的字段名稱列表,這將允許在更改列表頁面上進行編輯。
        6. 其它參見https://docs.djangoproject.com/en/1.11/ref/contrib/admin/
        
        
    • 數據庫表管理

      • 修改模型類字段的顯示名字

        • 模型類各字段的第一個參數爲verbose_name,此字段顯示的名字會在後臺數據庫管理頁面顯示

        • 通過 verbose_name 字段選項,修改顯示名稱示例如下:

          title = models.CharField(
              max_length = 30,
              verbose_name='顯示名稱'
          )
          
      • 通過Meta內嵌類 定義模型類的屬性及展現形式

        • 模型類可以通過定義內部類class Meta 來重新定義當前模型類和數據表的一些屬性信息

        • 用法格式如下:

          class Book(models.Model):
              title = CharField(....)
              class Meta:
                  1. db_table = '數據表名'
                      - 該模型所用的數據表的名稱。(設置完成後需要立馬更新同步數據庫)
                  2. verbose_name = '單數名'
                      - 給模型對象的一個易於理解的名稱(單數),用於顯示在/admin管理界面中
                  3. verbose_name_plural = '複數名'
                      - 該對象複數形式的名稱(複數),用於顯示在/admin管理界面中
          
        • 示例:

          class Meta:
              db_table = 'book_table'  # 將原數據表名"bookstore_book" 換爲 "book_table",請查看數據表
              verbose_name = 'booooook'
              verbose_name_plural = 'booksssssss'  # 去127.0.0.1:8000/admin下看看哪兒變化了?
          

  • 數據表關聯關係映射 Relationship Map

    • 在關係型數據庫中,通常不會把所有數據都放在同一張表中,這樣做會額外佔用內存空間

    • 在關係列數據庫中通常用表關聯來解決數據庫

    • 常用的表關聯方式有三種:

      • 一對一映射:如 一張身份證對應一個人
      • 一對多映射:如 一個班級可以有多名學生
      • 多對多映射:如 一個學生可以報多個課程,一個課程可以有多個學生學習
    • 一對一映射

      • 一對一是表示現實事物間存在的一對一的對應關係。

      • 如:一個家庭只有一個戶主,一個男人有一個妻子,一個人有一個唯一的指紋信息等

      • 語法:

        在關聯的兩個類中的任何一個類中:
        class A(model.Model):
            ...
        
        class B(model.Model):
            屬性 = models.OneToOneField(A)
        
      • 用法實例:

      • 1、創建作家和妻子類

        # file : xxxxxxxx/models.py
        from django.db import models
        
        class Author(models.Model):
            '''作家模型類'''
            name = models.CharField('作家', max_length=50)
        
        class Wife(models.Model):
            '''作家妻子模型類'''
            name = models.CharField("妻子", max_length=50)
            author = models.OneToOneField(Author)  # 增加一對一屬性
        
      • 2、查詢

        • 在 Wife 對象中,通過 author 屬性找到對應的author對象
        • 在 Author 對象中,通過 wife 屬性找到對應的wife對象
      • 3、創始一對一的數據記錄

        from . import models
        author1 = models.Author.objects.create(name='陳老師')
        wife1 = models.Wife.objects.create(name='陳夫人', author=author1)  # 關聯王老師
        author2 = models.Author.objects.create(name='小米老師')  # 一對一可以沒有數據對應的數據 
        
      • 4、一對一數據的相互獲取

        • 正向獲取,直接通過關聯屬性查詢即可

          # 通過 wife 找 author
          from . import models
          wife = models.Wife.objects.get(name='陳夫人')
          print(wife.name, '的老公是', wife.author.name)
          
        • 反向查詢

          • 通過反向引用屬性查詢

          • 反向引用屬性爲實例對象.引用類名(小寫),如作家的反向引用爲作家對象.wife

          • 當反向引用不存在時,則會觸發異

            # 通過 author.wife 引用屬性 找 wife,如果沒有對應的wife剛觸發異常
            author1 = models.Author.objects.get(name='陳老師')
            print(author1.name, '的妻子是', author1.wife.name)
            author2 = models.Author.objects.get(name='小米老師')
            try:
                print(author2.name, '的妻子是', author2.wife.name)
            except:
                print(author2.name, '還沒有妻子')
            
      • 作用:
                  主要是解決常用數據不常用數據的存儲問題,把經常加載的一個數據放在主表中,不常用數據放在另一個副表中,這樣在訪問主表數據時不需要加載副表中的數據以提高訪問速度提高效率和節省內存空間,如經常把書的內容和書名建成兩張表,因爲在網站上經常訪問書名等信息,但不需要得到書的內容。

    • 一對多映射

      • 一對多是表示現實事物間存在的一對多的對應關係。

      • 如:一個學校有多個班級,一個班級有多個學生, 一本圖書只能屬於一個出版社,一個出版社允許出版多本圖書

      • 用法:

        • 當一個A類對象可以關聯多個B類對象時

          class A(model.Model):
              ...
          
          class B(model.Model):
              屬性 = models.ForeignKey(多對一中"一"的模型類, ...)
          
        • 外鍵類 ForeignKey

          • 構造函數:
            ForeignKey(to, on_delete, **options)
            
          • 常用參數:
            • on_delete
              1. models.CASCADE 級聯刪除。 Django模擬SQL約束ON DELETE CASCADE的行爲,並刪除包含ForeignKey的對象。
              2. models.PROTECT 拋出ProtectedError 以阻止被引用對象的刪除;
              3. SET_NULL 設置ForeignKey null;只有null是True纔有可能。
              4. SET_DEFAULT 將ForeignKey設置爲其默認值;必須設置ForeignKey的默認值。
              5. 其它參請參考文檔 https://yiyibooks.cn/xx/Django_1.11.6/ref/index.html ForeignKey部分
            • **options 可以是常用的字段選項如:
        • 示例:

          • 有兩個出版社對應五本書的情況:

            • 清華大學出版社有如下書:
              1. C++
              2. Java
              3. Python
            • 北京大學出版社有如下書:
              1. 西遊記
              2. 水滸傳
          • 定義一對多類:

            # file: myorm/models.py
            from django.db import models
            class Publisher(models.Model):
                '''出版社'''
                name = models.CharField('名稱', max_length=50, unique=True)
            
            class Book(models.Model):
                title = models.CharField('書名', max_length=50)
                publisher = models.ForeignKey(Publisher, null=True)
            
          • 創建一對多的對象:

            # file: xxxxx/views.py
            from . import models
            pub1 = models.Publisher.objects.create(name='清華大學出版社')
            models.Book.objects.create(title='C++', publisher=pub1)
            models.Book.objects.create(title='Java', publisher=pub1)
            models.Book.objects.create(title='Python', publisher=pub1)
            
            pub2 = models.Publisher.objects.create(name='北京大學出版社')
            models.Book.objects.create(title='西遊記', publisher=pub2)
            models.Book.objects.create(title='水滸', publisher=pub2)
            
          • 查詢:

            • 通過多查一:

              # 通過一本書找到對應的出版社
              abook = models.Book.objects.get(id=1)
              print(abook.title, '的出版社是:', abook.publisher.name)
              
            • 通過一查多:

              # 通過出版社查詢對應的書
              pub1 = models.Publisher.objects.get(name='清華大學出版社')
              books = pub1.book_set.all()  # 通過book_set 獲取pub1對應的多個Book數據對象
              # books = models.Book.objects.filter(publisher=pub1)  # 也可以採用此方式獲取
              print("清華大學出版社的書有:")
              for book in books:
                  print(book.title)
              
      • 多對多映射

        • 多對多表達對象之間多對多複雜關係,如: 每個人都有不同的學校(小學,初中,高中,…),每個學校都有不同的學生…

        • 語法:

          在關聯的兩個類中的任意一個類中,增加:
          屬性 = models.ManyToManyField(Entry)
          
        • 示例:

          一個作者可以出版多本圖書
          一本圖書可以被多名作者同時編寫
          
          class Author(models.Model):
              xxxx xxxx
          
          class Book(models.Model):
              xxxx xxxx
          
              authors = models.ManyToManyField(Author)
          
        • 數據查詢:

          • 通過 Book 查詢對應的所有的 Authors

            可以通過authors表示對應所有Author的查詢對象
            
            book.authors.all() -> 獲取 book 對應的所有的author的信息
            
            book.authors.filter(age__gt=80) -> 獲取book對應的作者中年齡大於80歲的作者的信息
            
          • 通過 Author 查詢對應的所有的Books

            Django會生成一個屬性 book_set 用於表示對對應的book的查詢對象相關操作
            author.book_set.all()
            author.book_set.filter()
            author.book_set.create(...)  # 創建新書並聯作用author
            author.book_set.add(book)   # 添加已有的書爲當前作者author
            author.book_set.clear()  # 刪除author所有並聯的書
            author.book_set.remove()  # 刪除所author所有並聯的書
            
          • 示例:

            • 多對多模型:

              class Author(models.Model):
                  '''作家模型類'''
                  name = models.CharField('作家', max_length=50)
                  def __str__(self):
                      return self.name
              class Book(models.Model):
                  title = models.CharField('書名', max_length=50)
                  author = models.ManyToManyField(Author, null=True)
                  def __str__(self):
                      return self.title
              
            • 多對多視圖操作:

              from django.http import HttpResponse
              
              from . import models
              
              def many2many_init(request):
                  # 創建兩人個作者
                  author1 = models.Author.objects.create(name='dayin')
                  author2 = models.Author.objects.create(name='xiaoyin')
              
                  # dayin和xiaoyin同時寫了一本Python
                  book11 = author1.book_set.create(title="Python")
                  author2.book_set.add(book11)  #
              
                  # xiaoyin還寫了兩本書
                  book21 = author2.book_set.create(title="C")  # 創建一本新書"C"
                  book22 = author2.book_set.create(title="C++")  # 創建一本新書"C++"
              
                  return HttpResponse("初始化成功")
              
              def show_many2many(request):
                  authors = models.Author.objects.all()
                  for auth in authors:
                      print("作者:", auth.name, '發出版了', auth.book_set.count(), '本書: ')
                      for book in books:
                          print('    ', book.title)
                  print("----顯示書和作者的關係----")
                  books = models.Book.objects.all()
                  for book in books:
                      auths = book.author.all()
                      print(book.title, '的作者是:', '、'.join([str(x.name) for x in auths]))
                  return HttpResponse("顯示成功,請查看服務器端控制檯終端")
              
            • 多對多最終的SQL結果:

              mysql> select * from myorm2_author;
              +----+-----------+
              | id | name      |
              +----+-----------+
              | 11 | dayin      |
              | 12 | xiaoyin    |
              +----+-----------+
              2 rows in set (0.00 sec)
              
              mysql> select * from myorm2_book;
              +----+--------+
              | id | title  |
              +----+--------+
              | 13 | Python |
              | 14 | C      |
              | 15 | C++    |
              +----+--------+
              3 rows in set (0.00 sec)
              
              mysql> select * from myorm2_book_author;
              +----+---------+-----------+
              | id | book_id | author_id |
              +----+---------+-----------+
              | 17 |      13 |        11 |
              | 20 |      13 |        12 |
              | 18 |      14 |        12 |
              | 19 |      15 |        12 |
              +----+---------+-----------+
              4 rows in set (0.00 sec)
              

  • Cookies 和 Session(會話)

    • Cookies

      • cookies是保存在客戶端瀏覽器上的存儲空間,通常用來記錄瀏覽器端自己的信息和當前連接的確認信息

      • cookies 在瀏覽器上是以鍵-值對的形式進行存儲的,鍵和值都是以ASCII字符串的形存儲(不能是中文字符串)

      • 在Django 服務器端來設置 設置瀏覽器的COOKIE 必須通過 HttpResponse 對象來完成

      • HttpResponse 關於COOKIE的方法

        • 添加、修改COOKIE
          • HttpResponse.set_cookie(key, value=’’, max_age=None, expires=None)

            • key:cookie的名字
            • value:cookie的值
            • expires:保存時長,以秒爲單位(s不寫)
          • 刪除Cookie

            • HttpResponse.delete_cookie(key)
            • 刪除指定的key 的Cookie。 如果key 不存在則什麼也不發生。
      • Django中的cookies

        • 使用 響應對象HttpResponse 等 將cookie保存進客戶端

        • 方法1:

          from django.http import HttpResponse
          resp = HttpResponse()
          resp.set_cookie('cookies名', cookies值, 超期時間)
          
        • 方法二, 使用render對象

          from django.shortcuts import render
          resp = render(request,'xxx.html',locals())
          resp.set_cookie('cookies名', cookies值, 超期時間)
          
        • 方法三, 使用redirect對象

          from django.shortcuts import redirect
          resp = redirect('/')
          resp.set_cookie('cookies名', cookies值, 超期時間)
          
      • 獲取cookie:

        • 通過 request.COOKIES 獲取客戶端的 COOKIES數據

          resp = redirect('/')
          resp.set_cookie('cookies名', cookies值, 超期時間)
          
      • 注:Chrome 瀏覽器 可能通過開發者工具的 Application >> Storage >> Cookies 查看和操作瀏覽器端所有的 Cookies 值

      • 示例:

        # file : <項目名>/urls.py
        from . import views
        
        urlpatterns = [
            path(r'^admin/', admin.site.urls),
            # 增刪改cookie
            path(r'^add_cookie', views.add_cookie),
            path(r'^mod_cookie/<int:d>', views.mod_cookie),
            path(r'^del_cookie', views.del_cookie),
            path(r'^show_cookie', views.show_cookie),
        ]
            
        # file : <項目名>/views.py
        from . import views
        from django.http import HttpResponse
        def add_cookie(request):
            responds = HttpResponse("已添加mycookie_var1,值爲123")
            responds.set_cookie('mycookie_var1', 123, 3600)
            return responds
        
        def mod_cookie(request,d):
            responds = HttpResponse("已修改mycookie_var1,新值爲"+d)
            responds.set_cookie('mycookie_var1', d, 3600)
            return responds
        
        def del_cookie(request):
            responds = HttpResponse("已刪除mycookie_var1")
            responds.delete_cookie('mycookie_var1')
            return responds
        
        def show_cookie(request):
            value = request.COOKIES.get('mycookie_var1', '沒有值!')
            print("cookie mycookie_var1 = ", value)
            return HttpResponse("mycookie_var1:" + value)
        
    • Session

      • session是在服務器上開闢一段空間用於保留瀏覽器和服務器交互時的重要數據

      • 每個客戶端都可以在服務器端有一個獨立的Session

      • http協議是無狀態的:每次請求都是一次新的請求,不會記得之前通信的狀態

      • 客戶端與服務器端的一次通信,就是一次會話

      • 實現狀態保持的方式:在客戶端或服務器端存儲與會話有關的數據

      • 存儲方式包括cookie、session,會話一般指session對象

      • 使用cookie,所有數據存儲在客戶端,注意不要存儲敏感信息

      • 推薦使用sesison方式,所有數據存儲在服務器端,在客戶端cookie中存儲session_id

      • 狀態保持的目的是在一段時間內跟蹤請求者的狀態,可以實現跨頁面訪問當前請求者的數據

      • 注意:不同的請求者之間不會共享這個數據,與請求者一一對應

      • 什麼是session

        • session - 會話
        • 在服務器上開闢一段空間用於保留瀏覽器和服務器交互時的重要數據
      • Django啓用Session

        • 在 settings.py 文件中
        • 項INSTALLED_APPS列表中添加:
          • ‘django.contrib.sessions’,
        • 項MIDDLEWARE_CLASSES列表中添加
          • ‘django.contrib.sessions.middleware.SessionMiddleware’,
      • session的基本操作:

        • Session對於象是一個 QueryDict 字典, 可以用類擬於字典的方式進行操作

        • 保存 session 的值到服務器

          • request.session[鍵] = 值
          • 如: request.session[‘KEY’] = VALUE
        • 獲取session的值

          • VALUE = request.session[‘KEY’]
          • VALUE = request.session.get(‘KEY’, 缺省值)
        • 刪除session的值

          • del request.session[‘KEY’]
        • 在 settings.py 中有關 session 的設置

          • SESSION_COOKIE_AGE 作用:指定sessionid在cookies中的保存時長 SESSION_COOKIE_AGE = 60*30
          • SESSION_EXPIRE_AT_BROWSER_CLOSE = True 設置只要瀏覽器關閉時,session就失效
        • 注: 當使用session時需要遷移數據庫,否則會出現錯誤

          $ python3 manage.py makemigrations
          $ python3 manage.py migrate
          
        • session 示例:

          # file : <項目名>/urls.py
          from . import  views
          
          urlpatterns = [
              path(r'^admin/', admin.site.urls),
              # 增刪改session
              path(r'^add_session', views.add_session),
              path(r'^mod_session/<int:d>', views.mod_session),
              path(r'^del_session', views.del_session),
              path(r'^show_session', views.show_session),
          ]
              
          # file : <項目名>/views.py
          from . import views
          from django.http import HttpResponse
          def add_session(request):
              request.session['mysession_var'] = 100
              responds = HttpResponse("添加session")
              return responds
          def mod_session(request, d):
              request.session['mysession_var'] = d
              responds = HttpResponse("修改session成功")
              return responds
          def del_session(request):
              try:
                  del request.session['mysession_var']
                  responds = HttpResponse("刪除session成功")
              except:
                  responds = HttpResponse("刪除session失敗")
              return responds
          def show_session(request):
              mysession_var = request.session.get('mysession_var', '沒有值!')
              print("mysession_var = ", mysession_var)
              return HttpResponse("mysession_var = " + str(mysession_var))
          

  • 中間件 Middleware

    • 中間件是 Django 請求/響應處理的鉤子框架。它是一個輕量級的、低級的“插件”系統,用於全局改變 Django 的輸入或輸出。

    • 每個中間件組件負責做一些特定的功能。例如,Django 包含一箇中間件組件 AuthenticationMiddleware,它使用會話將用戶與請求關聯起來。

    • 他的文檔解釋了中間件是如何工作的,如何激活中間件,以及如何編寫自己的中間件。Django 具有一些內置的中間件,你可以直接使用。它們被記錄在 built-in middleware reference 中。

    • 中間件類:

      • 中間件類須繼承自 django.utils.deprecation.MiddlewareMixin類

      • 中間件類須實現下列五個方法中的一個或多個:

        • def process_request(self, request): 執行視圖之前被調用,在每個請求上調用,返回None或HttpResponse對象
        • def process_view(self, request, callback, callback_args, callback_kwargs): 調用視圖之前被調用,在每個請求上調用,返回None或HttpResponse對象
        • def process_response(self, request, response): 所有響應返回瀏覽器之前被調用,在每個請求上調用,返回HttpResponse對象
        • def process_exception(self, request, exception): 當處理過程中拋出異常時調用,返回一個HttpResponse對象
        • def process_template_response(self, request, response): 在視圖剛好執行完畢之後被調用,在每個請求上調用,返回實現了render方法的響應對象
      • 注: 中間件中的大多數方法在返回None時表示忽略當前操作進入下一項事件,當返回HttpResponese對象時表示此請求結果,直接返回給客戶端

    • 編寫中間件類:

      # file : middleware/mymiddleware.py
      from django.http import HttpResponse, Http404
      from django.utils.deprecation import MiddlewareMixin
      
      class MyMiddleWare(MiddlewareMixin):
          def process_request(self, request):
              print("中間件方法 process_request 被調用")
      
          def process_view(self, request, callback, callback_args, callback_kwargs):
              print("中間件方法 process_view 被調用")
      
          def process_response(self, request, response):
              print("中間件方法 process_response 被調用")
              return response
      
          def process_exception(self, request, exception):
              print("中間件方法 process_exception 被調用")
      
          def process_template_response(self, request, response):
              print("中間件方法 process_template_response 被調用")
              return response
      
    • 註冊中間件:

      # file : settings.py
      MIDDLEWARE = [
          ...
          'middleware.mymiddleware.MyMiddleWare',
      ]
      
    • 中間件的執行過程

    • 跨站請求僞造保護 CSRF

      • 跨站請求僞造攻擊

        • 某些惡意網站上包含鏈接、表單按鈕或者JavaScript,它們會利用登錄過的用戶在瀏覽器中的認證信息試圖在你的網站上完成某些操作,這就是跨站請求僞造。
      • CSRF

        Cross-Site Request Forgey
        跨     站點   請求    僞裝
        
      • 說明:

        • CSRF中間件和模板標籤提供對跨站請求僞造簡單易用的防護。
      • 作用:

        • 不讓其它表單提交到此 Django 服務器
      • 解決方案:

        • 取消 csrf 驗證(不推薦)
          • 刪除 settings.py 中 MIDDLEWARE 中的 django.middleware.csrf.CsrfViewMiddleware 的中間件
        • 開放驗證
          在視圖處理函數增加: @csrf_protect
          @csrf_protect
          def post_views(request):
              pass
          
        • 通過驗證
          需要在表單中增加一個標籤 
          {% csrf_token %}
          

  • Django中的forms模塊

    • 在Django中提供了 forms 模塊,用forms 模塊可以自動生成form內部的表單控件,同時在服務器端可以用對象的形式接收並操作客戶端表單元素,並能對錶單的數據進行服務器端驗證

    • forms模塊的作用:

      • 通過 forms 模塊,允許將表單與class相結合,允許通過 class 生成表單
    • 使用 forms 模塊的步驟

      • 1、在應用中創建 forms.py

      • 2、導入 django 提供的 forms

        • from django import forms
      • 3、創建class,一個class會生成一個表單

        • 定義表單類
         class ClassName(forms.Form):
                ...
        
      • 4、在 class 中創建類屬性

        • 一個類屬性對應到表單中是一個控件
      • 5、利用Form 類型的對象自動成表單內容

      • 6、讀取form表單並進行驗證數據

    • forms.Form 的語法

      • 屬性 = forms.Field類型(參數)
      • 1、類型
        class XXX(froms.Form):
            forms.CharField() : 文本框 <input type="text">
            forms.ChoiceField() : 下拉選項框 <select>
            forms.DateField() : 日期框 <input type="date">
            ... ...
        
      • 2、參數
        • label

          • 控件前的文本
        • widget

          • 指定小部件
        • initial

          • 控件的初始值(主要針對文本框類型)
        • required

          • 是否爲必填項,值爲(True/False)
    • form 表單示例

      • 手動實現Form 表單:

        <form action="/test_form1" method="post">
            <div>
                <label for="id_input_text">請輸入內容:</label> <input type="text" name="input_text" id="id_input_text" />
            </div>
            <button type="submit">提交</button>
        </form>
        
      • Django Form 實現 Form 表單

        class MySearch(forms.Form):
            input_text = forms.CharField(label = '請輸入內容')
        
    • 在模板中解析form對象

      • 方法

        • 需要自定義
        • 表單中的按鈕需要自定義
      • 解析form對象

        在 視圖中創建form對象併發送到模板中解析.
        ex:
            form = XXXForm()
            return render(request,'xx.html',locals())
        
      • 手動解析 {% for field in form %} field : 表示的是form對象中的每個屬性(控件) {{field.label}} : 表示的是label參數值 {{field}} : 表示的就是控件 {% endfor %}

      • 自動解析

        • {{form.as_p}} 將 form 中的每個屬性(控件/文本)都使用p標記包裹起來再顯示
        • {{form.as_ul}} 將 form 中的每個屬性(控件/文本)都使用li標記包裹起來再顯示。注意:必須手動提供ol 或 ul 標記
        • {{form.as_table}} 將 form 中的每個屬性(控件/文本)都使用tr標記包裹起來再顯示,注意:必須手動提供table標記
    • Field 內置小部件 - widget

      • 什麼是小部件
        • 表示的是生成到網頁上的控件以及一些其他的html屬性
          message=forms.CharField(widget=forms.Textarea)
          upwd=forms.CharField(widget=forms.PasswordInput)
          
        • 常用的小部件類型

    • 小部件的使用

      • 繼承自forms.Form

        • 基本版
          • 語法:

            屬性 = forms.CharField() #無預選值使用
                text,password,email,url,textarea,checkbox
            屬性 = forms.ChoiceField() #有預選值使用
                checkbox,radio,select
            
            屬性 = forms.CharField(
                label='xxx',
                widget=forms.小部件類型
            )
            
          • 示例:

            upwd = forms.CharField(
                label='用戶密碼',
                widget=forms.PasswordInput
            )
            
            message = forms.CharField(
                label='評論內容',	
                widget=forms.Textarea
            )
            
      • 高級版

        • 特徵

          • 在指定控件類型的基礎之上還能指定控件的一些html屬性值
        • 語法

              屬性 = forms.CharField(
                  label='xxx',
                  widget=forms.小部件類型(
                      attrs={
                          'html屬性名':'值',
                          'html屬性名':'值',
                      }
                  )
              )
          
        • 文檔參見https://yiyibooks.cn/xx/Django_1.11.6/topics/forms/index.html#forms-in-django

  • Django之form表單驗證

    • django form 提供表單和字段驗證

    • 當在創建有不同的多個表單需要提交的網站時,用表單驗證比較方便驗證的封裝

    • 當調用form.is_valid() 返回True表示當前表單合法,當返回False說明表單驗證出現問題

    • 驗證步驟:

      • 1、先對form.XXXField() 參數值進行驗證,比如:min_length,max_length, validators=[…],如果不符合form.is_valid()返回False
      • 2、對各自from.clean_zzz屬性名(self): 方法對相應屬性進行驗證,如果驗證失敗form.is_valid()返回False
      • 3、調用form.clean(self): 對錶單的整體結構進行驗證,如果驗證失敗form.is_valid()返回False
      • 以上驗證都成功 form.is_valid()返回True
    • 驗證方法:

      • validators = [驗證函數1, 驗證函數1]

        • 驗證函數驗證失敗拋出forms.ValidationError
        • 驗證成功返回None
      • def clean_xxx屬性(self):

        • 驗證失敗必須拋出forms.ValidationError
        • 驗證成功必須返回xxx屬性的值
      • def clean(self):

        • 驗證失敗必須拋出forms.ValidationError
        • 驗證成功必須返回 self.cleaned_data
    • 文檔參見https://yiyibooks.cn/xx/Django_1.11.6/topics/forms/index.html#forms-in-django

    • 驗證示例

      
      from django import forms
      import re
      
      mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
      def mobile_validate(value):
          if not mobile_re.match(value):
              raise forms.ValidationError('手機號碼格式錯誤')
      
      class RegisterForm(forms.Form):
          username = forms.CharField(label='用戶名')
          password = forms.CharField(label='請輸入密碼', widget=forms.PasswordInput)
          password2 = forms.CharField(label='再次輸入新密碼', widget=forms.PasswordInput)
          mobile = forms.CharField(label='電話號碼', validators=[mobile_validate])
      
          def clean(self):
              pwd1 = self.cleaned_data['password']
              pwd2 = self.cleaned_data['password2']
              if pwd1 != pwd2:
                  raise forms.ValidationError('兩次密碼不一致!')
              return self.cleaned_data  # 必須返回cleaned_data
      
          def clean_username(self):
              username = self.cleaned_data['username']
              if len(username) < 6:
                  raise forms.ValidationError("用戶名太短")
              return username
      

end…

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