Django组件介绍

我不是女神ヾ 2022-05-12 08:28 316阅读 0赞

文章目录

  • Django组件介绍
      1. 分页器的使用
      • 1.1 数据库内插入大量数据
      • 1.2 导入模块
      • 1.3 实例化一个分页器
      • 1.4 分页器对象相关的方法
      • 1.5 一个简单的分页示例
      1. forms组件
      • 2.1 检验字段功能
        • 2.11 导入forms组件
        • 2.12 使用forms组件创建一个类
        • 2.13 实例化一个forms对象
        • 2.14 查看校验字段结果
      • 2.15 渲染标签功能
        • 2.16 首先实例化一个forms类
        • 2.17 在模板中使用forms
      • 2.2 使用forms显示重置界面
      • 2.3 如何显示错误信息
        • 2.31 首先将实例化的forms对象传入HTML
        • 2.32 在HTML模板中调用相应的对象
      • 2.4 forms的参数配置
        • 2.41 导入模块
        • 2.42 设置forms组件在模板中生成的元素类型
        • 2.43 设置forms组件在模板中生成元素的属性
      • 2.5 校验的局部钩子
        • 2.51 原理
        • 2.52 先导入错误类型
        • 2.53 然后在forms类中创建一个`clean_字段`的函数
        • 2.54 使用`cleaned_data`获取校验成功的值
        • 2.55 示例
      • 2.6 全局钩子
        • 2.61 原理
        • 2.62 在forms类中创建一个`clean`函数
        • 2.63 示例
      1. 中间件
      • 3.1 什么是中间件?
      • 3.2 自定义中间件
        • 3.21 创建一个存放中间件的文件夹,如my_middlewares.py
        • 3.22 导入相应的类
        • 3.23 创建相应的类(必须继承MiddlewareMixin)
        • 3.24 在MIDDLEWARE数组中注册该中间件
        • 3.25 中间件有什么作用?
        • 3.26 主要方法
      • 3.3 使用示例
        • 3.31 服务器页面加一个用户验证
        • 3.32 IP访问评率限制

Django组件介绍

1. 分页器的使用

分页器在页面中非常常见,当数据库条数数据过多时,页面一次性显示不好看时,我们可以使用分页器,将数据分几次显示。

1.1 数据库内插入大量数据

  1. Booklist=[]
  2. for i in range(100):
  3. Booklist.append(Book(title="book"+str(i),price=30+i*i))
  4. Book.objects.bulk_create(Booklist)

使用对象下面的bulk_create(),可以实现批量插入

1.2 导入模块

from django.core.paginator import Paginator

1.3 实例化一个分页器

paginator = Paginator(book_list,8) 第一个为数据列表,第二个为每一页数据

1.4 分页器对象相关的方法






















方法 作用
paginator.count() 数据总数
paginator.num_pages() 总页数
paginator.page_range() 页码的迭代器

获取第n页数据
current_page = paginator.page(1)获取第一页的列表






























方法 作用
current_page.object_list 获取第n页对象列表
current_page.has_next() 是否有下一页
current_page.next_page_number() 下一页的页码
current_page.has_previous() 是否有上一页
current_page.previous_page_number() 上一页的页码

注意:如果在paginator.page(1)输入的页码数小于1或者大于最大页数,会报EmptyPage错误。
捕捉EmptyPage错误方法

  1. from django.core.paginator import EmptyPage
  2. 引入错误,使用try捕捉错误
  3. try:
  4. 内容
  5. except EmptyPage as e:
  6. current_page=paginator.page(1)

1.5 一个简单的分页示例

views.py

  1. def books(request):
  2. book_list = Book.objects.all()
  3. from django.core.paginator import Paginator,EmptyPage
  4. paginator = Paginator(book_list,3)
  5. num_pages = paginator.num_pages
  6. current_page_num = int(request.GET.get("page",1))
  7. if num_pages > 11:
  8. if current_page_num < 5:
  9. page_range = range(1,11)
  10. elif current_page_num+5 > num_pages:
  11. page_range = range(num_pages-10,num_pages+1)
  12. else:
  13. page_range = range(current_page_num-5,current_page_num+5)
  14. else:
  15. page_range = paginator.page_range
  16. try:
  17. current_page = paginator.page(current_page_num)
  18. except EmptyPage as e:
  19. current_page = paginator.page(1)
  20. return render(request,"book.html",locals())

book.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>分页练习</title>
  6. <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
  7. <script
  8. src="https://code.jquery.com/jquery-3.3.1.js"
  9. integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60="
  10. crossorigin="anonymous"></script>
  11. </head>
  12. <body>
  13. <p>OK</p>
  14. <table class="table table-striped">
  15. <tbody>
  16. {#显示当前页面#}
  17. {% for book in current_page %}
  18. <tr>
  19. <td>{
  20. { book.nid }}</td>
  21. <td>{
  22. { book.title }}</td>
  23. <td>{
  24. { book.price}}</td>
  25. </tr>
  26. {% endfor %}
  27. </tbody>
  28. </table>
  29. {#显示页码#}
  30. <ul class="pagination">
  31. {% if current_page.has_previous %}
  32. <li>
  33. <a href="?page={
  34. { current_page.previous_page_number }}" aria-label="Previous">
  35. <span aria-hidden="true">«</span>
  36. </a>
  37. </li>
  38. {% else %}
  39. <li class="disabled">
  40. <a href="" aria-label="Previous">
  41. <span aria-hidden="true">«</span>
  42. </a>
  43. </li>
  44. {% endif %}
  45. {% for item in page_range %}
  46. {% if item == current_page_num %}
  47. <li class="active"><a href="?page={
  48. { item }}">{
  49. { item }}</a></li>
  50. {% else %}
  51. <li><a href="?page={
  52. { item }}">{
  53. { item }}</a></li>
  54. {% endif %}
  55. {% endfor %}
  56. {% if current_page.has_next %}
  57. <li>
  58. <a href="?page={
  59. { current_page.next_page_number }}" aria-label="Next">
  60. <span aria-hidden="true">»</span>
  61. </a>
  62. </li>
  63. {% else %}
  64. <li class="disabled">
  65. <a href="" aria-label="Next">
  66. <span aria-hidden="true">»</span>
  67. </a>
  68. </li>
  69. {% endif %}
  70. </ul>
  71. </body>
  72. {#<script>#}
  73. {# $(".pagination li a").click(function () {#}
  74. {# $(this).parent().addClass("active").siblings("li").removeClass("active")#}
  75. {# })#}
  76. {#</script>#}
  77. </html>

2. forms组件

forms组件主要功能是检验字段的功能,校验表单中的键值对的功能

2.1 检验字段功能

2.11 导入forms组件

from django import forms

2.12 使用forms组件创建一个类

  1. class UserForm(forms.Form):
  2. name = forms.CharField(min_length=4)
  3. email=forms.EmailField()

name字段最小不得小于4个字节,email字段必须邮箱格式
注意:该类必须继承forms.Form
只校验UserForm中的字段,传入的其他字段会被忽视,不会校验。forms存在该字段,校验时该字段就不能为空

一些常用的校验函数及其参数


































校验函数 解释
CharField 校验字符串,可以设置max_length最大长度或最小长度min_length
DecimalField 校验验证数字,前后空格会被忽略,max_valuemin_value控制总长度,并应作为decimal.Decimal值给出。max_digits允许的小数+整数总位数;decimal_places允许的最大小数位数。
EmailField 是否为有效的电子邮件地址,可选参数max_lengthmin_length
FileField 非空文件数据是否已绑定到表单,max_length文件最大大小和allow_empty_file文件是否可以为空
FloatField 验证给定值是否为float,可选max_value并且min_value
IntegerField 验证给定值是否为整数。可选max_valuemin_value

2.13 实例化一个forms对象

将需要验证的表单值传入,检验是否合法
form=UserForm({"name":"yuan","email":"123"})
也可以直接传入POST字典(但是前段键值必须与form一一对应)
form = UserForm(request.POST)

2.14 查看校验字段结果






















相关API 功能
form.is_valid() 校验全部通过返回True,否则返回False
form.cleaned_data 返回字典,可以查看校验成功的字段(键值都放入)
form.errors 可以查看校验失败的字段(键为校验错误的键,值为错误信息的列表)

2.15 渲染标签功能

forms组件还可以自动为我们在form表单中渲染校验字段的表单

具体方法如下

2.16 首先实例化一个forms类

form=UserForm() 不用传值

2.17 在模板中使用forms

方式一: 使用标签{ { form.字段 }}可以渲染出相应的input标签
在HTML中

  1. <form action="" method="post">
  2. {% csrf_token %}
  3. <p>用户名:{
  4. { form.name }}</p>
  5. <p>密码:{
  6. { form.pwd }}</p>
  7. <p>再次确认密码:{
  8. { form.re_pwd }}</p>
  9. <p>邮箱:{
  10. { form.email }}</p>
  11. <p>电话:{
  12. { form.tel }}</p>
  13. <input type="submit" value="注册">
  14. </form>

视图函数中
form=UserForm()
forms组件将自动将生成标签name属性变成相应的字段名
比如说<p>用户名:{ { form.name }}</p>
等同于<p>用户名:<input type="text" name="name"></p>

方式二: 使用for循环标签

  1. <form action="" method="post">
  2. {% csrf_token %}
  3. {% for field in form %}
  4. <p>
  5. <label>{
  6. { field.label }}</label>
  7. {
  8. { field }} <span>{
  9. { field.errors.0 }}</span>
  10. </p>
  11. {% endfor %}
  12. <input type="submit" value="注册">
  13. </form>

使用{ { form.字段.label }}可以渲染出相应的label标签
注意:label标签默认显示的是字段名,如果想修改label标签显示的内容,可以在创建forms类时指定

  1. class UserForm(forms.Form):
  2. name = forms.CharField(min_length=4,label="用户名")
  3. email=forms.EmailField(label="邮箱")

使用label参数进行指定,用这个UserForm渲染出的效果相当于

  1. <p>用户名:{
  2. { form.name }}</p>
  3. <p>邮箱:{
  4. { form.email }}</p>

方式三:

  1. <p>方式三</p>
  2. <form action="" method="post">
  3. {% csrf_token %}
  4. {
  5. { form.as_ul }}
  6. <input type="submit" value="注册">
  7. </form>

使用{ { form.as_ul }}可以自动渲染所有字段,每个字段使用label和input渲染,并且用ul包裹
还可以选择用as_p(),as_table()分别是用ptable标签包裹

2.2 使用forms显示重置界面

当用户表单输入错误时,我们可能自己传入参数,设置各个input的value值,来渲染出一个重置页面,使用forms组件,可以快速渲染出一个重置界面
只需简单设置几步即可

  1. def register(request):
  2. if request.method =="POST":
  3. form = UserForm(request.POST)
  4. if form.is_valid():
  5. return HttpResponse("ok")
  6. else:
  7. return render(request,"register.html",locals())
  8. else:
  9. form = UserForm()
  10. return render(request,"register.html",locals())

简单说,如果用户使用浏览器访问页面时,发送的是get请求,我们使用form = UserForm()传入一个没有参数的forms对象,在浏览器中,将自动渲染出各个字段的空白标签
如果用户提交表单时,我们实例化一个form = UserForm(request.POST)带有参数的forms对象,同样的,浏览器中会渲染出提交表单传入的参数内容。
也就是说,输入错误时,返回的表单中用户输入的内容不会为空,会是用户上次输入错误的内容

2.3 如何显示错误信息

如果我们想在校验数据之后,将错误信息输入到HTML页面上,我们可以这样做

2.31 首先将实例化的forms对象传入HTML

  1. form = UserForm()
  2. return render(request,"register.html",locals())

这样直接将局部变量全部当映射到HTML模板中(包括form)

2.32 在HTML模板中调用相应的对象

  1. <form action="" method="post">
  2. {% csrf_token %}
  3. <p>用户名:{
  4. { form.name }}<span>{
  5. { form.name.errors.0 }}</span></p>
  6. <p>密码:{
  7. { form.pwd }}<span>{
  8. { form.pwd.errors.0 }}</span></p>
  9. <p>再次确认密码:{
  10. { form.re_pwd }}<span>{
  11. { form.re_pwd.errors.0 }}</span></p>
  12. <p>邮箱:{
  13. { form.email }}<span>{
  14. { form.email.errors.0 }}</span></p>
  15. <p>电话:{
  16. { form.tel }}<span>{
  17. { form.tel.errors.0 }}</span></p>
  18. <input type="submit" value="注册">
  19. </form>

使用{ { form.字段.errors.0 }}标签 如果相应字段错误,可以渲染出相应的错误信息({ {form.字段.errors}}是一个错误列表,我们使用{ { form.字段.errors.0 }}只取出第一个错误信息)

2.4 forms的参数配置

使用widgets模块,我们可以给forms类中的字段设置相应的参数

2.41 导入模块

form django.forms import widgets

2.42 设置forms组件在模板中生成的元素类型

如果我们设置一个校验字段为CharField类型,那么在HTML模板中生成的标签即为<input type='text'>类型
如果我们想修改生成的标签类型,怎么办?
示例:
pwd =forms.CharField(min_length=4,widget=widgets.PasswordInput())
使用widget参数可以设置标签类型,PasswordInput()代表将自动生成```类型标签

2.43 设置forms组件在模板中生成元素的属性

如果我们想给每一个生成的元素中默认添加某些属性,我们可以在元素类型函数中使用attrs参数
示例:name = forms.CharField(min_length=4,widget=widgets.TextInput(attrs={"class":"form-control"}))
在每个默认生成的元素中添加class属性,值为form-control
通过attrs中存放需要设置键值对

2.5 校验的局部钩子

如果上述对字段的校验条件太少,不能满足我们的需要,我们可以对每个字段自定义校验的内容,就要使用局部钩子
使用方法

2.51 原理

当我们调用forms对象下的s_valid()函数时,将会进行字段校验;校验成功放入clean_data字典中,校验失败抛出异常,然后异常处理函数将校验失败的字段和错误信息存入errors字典中。而在django校验成功时,特意留下一个钩子,用来给用户自定义函数
django部分代码:

  1. if hasattr(self, 'clean_%s' % name):
  2. value = getattr(self, 'clean_%s' % name)()
  3. self.cleaned_data[name] = value

2.52 先导入错误类型

from django.core.exceptions import ValidationError
ValidationError是用来抛出异常时的错误类型

2.53 然后在forms类中创建一个clean_字段的函数

def clean_name(self):

2.54 使用cleaned_data获取校验成功的值

val = self.cleaned_data.get("name")
使用cleaned_data可以获取的校验成功的字典

2.55 示例

验证手机号码字段是否是十一位

  1. def clean_tel(self):
  2. val = self.cleaned_data.get("tel")
  3. if len(val)==11:
  4. return val
  5. else:
  6. raise ValidationError("手机号位数错误")

取出由forms校验成功的电话号码,对其进行校验,如果满足条件,将原来取出的字段原样返回,否则抛出异常

2.6 全局钩子

如果我们想对多个字段之间的关系进行校验,比如说确认密码和密码需要相同,但用局部钩子只能对单个字段的值进行校验。这是候我们需要全局钩子
第一步,同样导入ValidationError类型的错误

2.61 原理

django同时也留一个clean函数,当用户想要对多个字段之间的关系进行校验时,直接覆盖掉这个函数,在函数中写出自己想校验的内容即可
django中部分代码
clean代码

  1. def clean(self):
  2. """
  3. Hook for doing any extra form-wide cleaning after Field.clean() has been
  4. called on every field. Any ValidationError raised by this method will
  5. not be associated with a particular field; it will have a special-case
  6. association with the field named '__all__'.
  7. """
  8. return self.cleaned_data

2.62 在forms类中创建一个clean函数

def clean(self):

2.63 示例

校验确认密码和密码是否相同

  1. def clean(self):
  2. pwd = self.cleaned_data.get("pwd")
  3. re_pwd = self.cleaned_data.get("re_pwd")
  4. if pwd and re_pwd:
  5. if pwd == re_pwd:
  6. return self.cleaned_data
  7. else:
  8. raise ValidationError("两次密码不一致")
  9. return self.cleaned_data

如果校验成功,返回原来的clean_data字段,校验失败抛出异常ValidationError

注意:

  1. 在模板中,单个字段校验失败的错误信息我们可以使用{ {form.字段.errors}}
    而全局钩子抛出的异常会被存入全局错误中,我们需要在python使用clean_errors = form.errors.get("__all__")获取全局错误信息,在模板中使用{ { clean_errors.0 }}获取错误信息
  2. 我们在校验时,还要判断if pwd and re_pwd:,代表如果单个字段校验失败,就不执行全局钩子。这样如果密码或者是确认密码格式不对,密码和确认密码也不相同时,只报一个密码或者是确认密码格式错误。

3. 中间件

3.1 什么是中间件?

request和respone之间的处理程序
settings.py中MIDDLEWARE数组中存储的就是中间件

  1. MIDDLEWARE = [
  2. 'django.middleware.security.SecurityMiddleware',
  3. 'django.contrib.sessions.middleware.SessionMiddleware',
  4. 'django.middleware.common.CommonMiddleware',
  5. 'django.middleware.csrf.CsrfViewMiddleware',
  6. 'django.contrib.auth.middleware.AuthenticationMiddleware',
  7. 'django.contrib.messages.middleware.MessageMiddleware',
  8. 'django.middleware.clickjacking.XFrameOptionsMiddleware',
  9. 'app01.my_middlewares.AuthMiddleware',
  10. 'app01.my_middlewares.IpLimitMiddleware',
  11. ]

中间件流程
客户端-》wsgiref模块-》中间件-》urls路由控制-》数据库MODEL,HTML模板

3.2 自定义中间件

3.21 创建一个存放中间件的文件夹,如my_middlewares.py

3.22 导入相应的类

from django.utils.deprecation import MiddlewareMixin

3.23 创建相应的类(必须继承MiddlewareMixin)

  1. class CustomerMiddleware(MiddlewareMixin)
  2. def process_request(self,request):
  3. print("Customer")

必须有request参数;不用返回值,让其默认返回none

3.24 在MIDDLEWARE数组中注册该中间件

  1. MIDDLEWARE = [
  2. ...
  3. ...
  4. ...
  5. "app01.my_middlewares.CustomerMiddleware",
  6. ]

3.25 中间件有什么作用?

只要浏览器访问服务器,就会访问中间件
作用:大部分视图函数要使用的代码就可以放到中间件中
比如,将登陆函数放到中间件中,访问服务器就会调用中间件,验证是否登录
使用中间件限制用户访问的频率

3.26 主要方法

在该类中,主要可以定义一下几个方法


























方法 定义
process_request def process_request(self,request):
process_response def process_response(self,request,response):
process_view process_view(self, request, callback, callback_args, callback_kwargs)|
process_exception def process_exception(self,request,exception):

注意:

  1. 每个类都必须传入request参数
  2. process_response必须有返回值,类型为响应体(传入的respone参数为视图函数返回的响应体)
  3. 如果中间件1的process_request直接返回HttpRespone,不会执行后面的中间件,会直接跳到中间件1的process_respone
  4. process_exception正常情况下不会执行,只有视图函数报错时才会执行;作用:在该函数下返回的响应体会替代原出错时的黄色报错界面,相当于捕获异常,处理异常的函数

执行顺序
正常情况下:
process_request-》url控制器-》process_view-》视图函数-》process_response
视图函数出错时候
process_request-》url控制器-》process_view-》视图函数出错-》process_exception-》process_response

setting.pyMIDDLEWARE列表执行顺序
当有多个中间件时,服务器发过来的数据依次从上向下执行函数,视图函数返回顺序时,从下向上执行
每个process_request将传过来的客户端的请求依次传给下一个process_request
每个process_response将传过来的响应体依次传给上一个process_response

例如:
process_request1-》process_request2-》url控制器-》process_view1-》》process_view2-》视图函数出错-》process_exception2-》process_exception1-》process_response2-》process_response1

3.3 使用示例

3.31 服务器页面加一个用户验证

如果我们想让一些页面在用户登录后才显示,我们除了可以使用用户认证装饰器装饰器以外,还可以使用中间件

  1. from django.utils.deprecation import MiddlewareMixin
  2. from django.shortcuts import redirect
  3. from authDemo import settings
  4. class AuthMiddleware(MiddlewareMixin):
  5. def process_request(self,request):
  6. if request.path in settings.WHITE_LIST:
  7. return None
  8. # 用户登录验证
  9. if not request.user.is_authenticated:
  10. return redirect("/login/")

settings.py里面创建一个WHITE_LIST列表,用来存放不需要加用户认证的url,比如登录,注册,注销url
如果用户没有登录,我们将其页面重定向到/login/

3.32 IP访问评率限制

如果我们想限制客户端ip的访问频率,我们可以使用中间件

  1. from django.utils.deprecation import MiddlewareMixin
  2. from django.shortcuts import redirect,HttpResponse
  3. from authDemo import settings
  4. import datetime
  5. class IpLimitMiddleware(MiddlewareMixin):
  6. def process_request(self,request):
  7. if request.META.get("HTTP_X_FORWARDED_FOR"):
  8. ip = request.META["HTTP_X_FORWARDED_FOR"]
  9. else:
  10. ip = request.META["REMOTE_ADDR"]
  11. now_min = datetime.datetime.now().minute
  12. if ip in settings.BLACK_LIST: #查询ip是否在黑名单内
  13. return HttpResponse("你已经被加入黑名单")
  14. elif ip in settings.IP_LIST:
  15. if settings.IP_LIST[ip]["min"] == now_min:
  16. settings.IP_LIST[ip]["times"] += 1
  17. if settings.IP_LIST[ip]["times"] >= settings.LIMIT_VISIT_TIMES: #判断用户访问次数是否太快,返回提醒用户
  18. if settings.IP_LIST[ip]["times"] >= settings.MAX_VISIT_TIMES: #如果用户访问次数非常多,加入黑名单
  19. settings.BLACK_LIST.append(ip)
  20. return HttpResponse("访问频率过快")
  21. else:
  22. settings.IP_LIST[ip]["times"] = 0
  23. settings.IP_LIST[ip]["min"] = now_min
  24. else:
  25. settings.IP_LIST[ip] = {"times":1,"min":now_min}
  1. settings.py里创建一个IP_LIST字典,用来存储客户端ip和其他信息(其实可以单独放入数据库一个表中,不过从数据库中读取没有内存中读取快,访问速度会受到影响)
  2. 如果用户使用代理request.META["REMOTE_ADDR"]抓不到真实地址,所以我们首先使用request.META["HTTP_X_FORWARDED_FOR"]来获取用户真实地址
  3. 我们将其用户ip和访问次数储存,在settings.py中设置一个常量LIMIT_VISIT_TIMES,超过这个次数不让用户访问网页;MAX_VISIT_TIMES超过这个次数,将这个ip加入黑名单

发表评论

表情:
评论列表 (有 0 条评论,316人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Django Form

    常用功能 From 组件主要有以下几大功能: 生成 HTML 标签 验证用户数据(显示错误信息) HTML Form 提交保留上次提交数据 初始