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…

猜你喜欢

转载自blog.csdn.net/weixin_42218582/article/details/103090833