Django框架

一、forms组件

froms组件简介

  • 1.自动校验数据
  • 2.自动生成标签
  • 3.自动展示信息

1、forms组件校验用户数据

关键词整理:

  • form_obj = views.MyForm(‘需要校验的数据(字典格式)’)
    • 将数据传入forms类,生成forms对象
  • forms对象.is_valid()
    • 判断传入的数据是否满足forms类中字段下的约束条件,返回True或False
  • forms对象.cleaned_data
    • 获取满足约束条件的数据(返回字典类型数据)
  • forms对象.erros
    • 获取没有满足的约束的数据及原因
小需求:获取用户数据并发送给后端校验 后端返回不符合校验规则的提示信息

    
from django import forms


class MyForm(forms.Form):
    username = forms.CharField(min_length=3, max_length=8)  # username字段最少三个字符最大八个字符
    age = forms.IntegerField(min_value=0, max_value=200)  # 年龄最小0 最大200
    email = forms.EmailField()  # 必须符合邮箱格式
    
 
校验数据的功能(初识)
	 form_obj = views.MyForm({'username':'jason','age':18,'email':'123'})
    form_obj.is_valid()  # 1.判断数据是否全部符合要求
    False  # 只要有一个不符合结果都是False
    form_obj.cleaned_data  # 2.获取符合校验条件的数据
    {'username': 'jason', 'age': 18}
    form_obj.errors  # 3.获取不符合校验规则的数据及原因
    {'email': ['Enter a valid email address.']}
1.只校验类中定义好的字段对应的数据 多传的根本不做任何操作
2.默认情况下类中定义好的字段都是必填的

2、form组件渲染标签

​ 通过在后端页面导入forms组件,定义forms类,在试图函数内生成forms对象,然后将forms对象回调给前端页面,可以通过forms组件内置方法生成表单标签

方式一:

​ 直接使用form对象点关键词的方式来生成标签,该方法封装层度高,会被自动生成关键词对应标签包裹,拓展性差,一般用于本地测试使用

关键词:
	1、form对象.as_p
	2、form对象.as_ul
	3、form对象.as_table


前端页面:
    <h1>forms组件渲染标签</h1>
        关键词:as_table
        注释:每个input标签都被P包裹
        {{ form_obj.as_p }}

        关键词:as_ul
        注释:以无需标题的方式渲染input标签
        {{ form_obj.as_ul }}

        关键词:as_table
        注释:在同一排渲染input标签
        {{ form_obj.as_table }}

方式二:

​ 使用form对象点名称空间内变量名,该方法不会被自动包裹上其他标签,只会生成该字段下对应的标签,假如对象内有非常多的字段,那么就需要反复编写,比较麻烦,封装层度低,拓展性强

<h1>forms组件渲染标签</h1>
{{ form_obj.name.label }}  # 生成字段名(字段名是字母时,首字母会自动大写)
{{ form_obj.name }}      # 生成字段名对应标签

{{ form_obj.age.label }}
{{ form_obj.age }}

{{ form_obj.gender.label }}
{{ form_obj.gender }}

方式三:

​ 在前端使用模板语法,将form对象进行for循环,可以批量产生对应字段的名字和标签,该方法编写简单,并且拓展性强,推荐使用

<h1>forms组件渲染标签</h1>
    {% for form in form_obj %}
        <p>
        {{ form.label }}  # 获取字段名(字段名是英文字母时首字母自动转大写)
        {{ form }}  # 生成字段名对应的标签
        </p>
    {% endfor %}

3、forms组件展示信息

​ 在使用forms对象来验证传入的用户数据信息时,一般都是直接在后端获取验证后的数据和没有通过的原因,但是在实际使用中,都是将这些信息反馈给前端用户查看,针对真个问题,有以下的方式进行处理

1、后端视图函数
    # 定义forms类,并限制约束条件
    class My_forms(forms.Form):
        name = forms.CharField(min_length=3, max_length=8)
        age = forms.IntegerField(min_value=0, max_value=105)
        gender = forms.CharField(min_length=1, max_length=3)


    # 函数内生成forms对象,返回给前端页面
    def home_func(request):
        # 1、生成forms对象
        form_obj = My_forms()
        # 2、判断请求方式
        if request.method == 'POST':
            # 3、如果是POST请求,直接获取用户大字典,并将字典内数据传入forms类生成新的forms对象
            form_obj = My_forms(request.POST)
            # 4、将新的forms对象传入前端
        return render(request, 'homepage.html', locals())

    
 2、前端页面
	<body>
    <h1>forms组件渲染标签</h1>
    <form action="" method="post" novalidate>
        {% for form in form_obj %}
        <p>
            {{ form.label }}
            {{ form }}
		{#  使用form点出报错信息打印在input的标签后#}
            {{ form.errors.0 }}
        </p>
    {% endfor %}
    <button> 提交 </button>
    </form>

由上图可以看到,打印出的的报错信息是英语,针对这个问题django提供了两种修改语言的方式:

  • 方式一:自定义内容
    • 方法:在视图层forms对象内,将各个字段后方的参数内添加关键字
    • error_messages:可以自定义报错信息

代码展示

username = forms.CharField(min_length=3, 
                 ax_length=8, label='用户名',
                 # 自定义报错信息关键参数
                 error_messages={
                     # 不满足条件1报错的信息
                     'min_length': '用户名最少三个字符',
                     # 为满足条件2报错的信息
                     'max_length': '用户名最多八个字符',
                     # 当用户没有输入报错的信息
                     'required': '用户名不能为空'
                            }
                        )

  • 方式二:修改系统语言环境
    • 方法:在django的settings配置中修改参数

通过导入from django.conf import global_settings模块,在global_settings中的LANGUAGES参数下,可以查看Django支持的语言,只需要将该参数前的字符串拷贝至LANGUAGE_CODE配置下将原数据已修改,就可以修改系统语言环境

代码展示

1、导入模块:from django.conf import global_settings
    
2、查看global_settings下LANGUAGES参数

3、将参数内字符拷贝,替换settings下LANGUAGE_COD的数据

4、forms组件校验补充

​ 之前说到forms组件在视图层定义类,可以在类下设置对字段进行约束的条件,针对约束,forms组件提供了三种方式,并且支持三种方式混合使用

  • 第一种:直接填写参数

    • 例如:max_length
  • 第二种:利用正则表达式

    • 需要导入模块
  • 第三种:钩子函数

    • 在类中定义函数

1.直接填写参数:设置字段,在字段后填写参数进行约束

class MyForm(forms.Form):
    username = forms.CharField(min_length=3, max_length=8)
    password = forms.CharField(min_length=3, max_length=8)
    confirm_pwd = forms.CharField(min_length=3, max_length=8)

2.利用正则表达式:

1、需要导入模块:
	from django.core.validators import RegexValidator
    
 2、在参数后填写正则表达式
    class MyForm(forms.Form):
        username = forms.CharField(min_length=.*{3}, max_length=.*{3})

3.钩子函数:在类中定义函数,是校验的最后一环,是在字段所有的校验参数之后触发

1、局部钩子(只校验某一个字段)
	# 函数名是固定编写的必须是’clean_字段名‘
	def clean_name(self):
        # 获取需要校验的数据
        name = self.cleaned_data.get('name')
        # 校验数据
        if name == 'kang':
            # 若未通过校验,将数据添加到报错信息中(第一个参数是报错的字段,第二个参数是报错信息)
            self.add_error('name', '用户名不得为kang')
         # 不管校验是否通过都需要将数据进行返回出去
         return name
    
2、全局钩子(检验所有字段)
	def clean(self):
        password = self.cleaned_data.get('password')
        confirm_pwd = self.cleaned_data.get('confirm_pwd')
        if not password == confirm_pwd:
            self.add_error('confirm_pwd', '两次密码不一致')
        return self.cleaned_data

5、forms组件参数补充

关键 描述
min_length 最小字符
max_length 最大字符
min_value 最小值
label 字段注释
error_messages 错误提示
validators 正则校验器(需要导入模块from django.core.validators import RegexValidator)
initial 默认值
required 是否必填
widget 控制标签的各项属性
  • widget参数
    • 用来控制input标签属性和CSS样式
widget=forms.widgets.PasswordInput(attrs={'class': 'form-control', 'username': 'jason'})

widget:
 	# 控制标签属性的关键词
    
forms.widgets.:
	# 固定编写格式
    
PasswordInput():
	# 控制input标签的属性(可以修改为其他字段)
 
attrs={'class': 'form-control', 'username': 'jason'}
	# 控制标签的样式、属性、ID、Class值

6、forms组件源码刨析

1 为什么局部钩子要写成clean_字段名,为什么要抛异常
2 入口在is_valid()
3 校验流程
	-先校验字段自己的规则(最大,最小,是否必填,是不是合法)
	-校验局部钩子函数
	-全局钩子校验
    
4 流程
	-is_valid()  --> return self.is_bound and not self.errors
	-self.errors: 方法包装成了数据属性
        -一旦有值,self.errors就不进行校验(之前调用过了)
	- self.full_clean():  核心
        
 if not self.is_bound:  # Stop further processing. 如果data没有值直接返回
    return
 
    def full_clean(self):
        """
        Clean all of self.data and populate self._errors and self.cleaned_data.
        """
        self._errors = ErrorDict()
        if not self.is_bound:  # Stop further processing.
            return
        self.cleaned_data = {}
        # If the form is permitted to be empty, and none of the form data has
        # changed from the initial data, short circuit any validation.
        if self.empty_permitted and not self.has_changed():
            return
 
        self._clean_fields()
        self._clean_form()
        self._post_clean()
        
     # 局部钩子执行位置  
    def _clean_fields(self):
        for name, field in self.fields.items():
            # value_from_datadict() gets the data from the data dictionaries.
            # Each widget type knows how to retrieve its own data, because some
            # widgets split data over several HTML fields.
            if field.disabled:
                value = self.get_initial_for_field(field, name)
            else:
                value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
            try:
                if isinstance(field, FileField):
                    initial = self.get_initial_for_field(field, name)
                    value = field.clean(value, initial)
                else:
                    value = field.clean(value)  # 字段自己的校验规则
                self.cleaned_data[name] = value  # 把校验后的数据放到cleaned_data
                if hasattr(self, 'clean_%s' % name):  # 判断有没有局部钩子
                    value = getattr(self, 'clean_%s' % name)() # 执行局部钩子
                    self.cleaned_data[name] = value  # 校验通过 把数据替换一下
            except ValidationError as e:  # 如果校验不通过,会抛异常,会被捕获
                self.add_error(name, e)  # 捕获后执行  添加到错误信息 errors是个列表 错误可能有多个
                
      
# 全局钩子执行位置
    def _clean_form(self):
        try:
            # 如果自己定义的form类中写了clean,他就会执行
            cleaned_data = self.clean()  
        except ValidationError as e:
            self.add_error(None, e) # key作为None就是__all__
        else:
            if cleaned_data is not None:
                self.cleaned_data = cleaned_data

二、modelform组件

modelfrom组件简介

​ 相比较于forms组件,该组件功能更为强大,将forms组件内较为麻烦的编写方式进行的升级,基本使用方法不变

​ 只做了解,并不会深入学习

1、字段约束

# 1、该组件在forms组件功能下,导入模块的方式不变
    from django import forms
    from app01 import models

# 2、将字段约束进行了集合,不用在单个编写
	# 先定义一个类,继承forms.ModelForm
	class MyModelForm(forms.ModelForm):
        # 再次定义一个类
        class Meta:
            # 使用models点出需要约束的表
            model = models.UserInfo
            # all拿出表内全部的字段
            fields = '__all__'
            # 字段的注释(会替换掉前端字段)
            labels = {
                'username':'用户名'
            }
            
# 3、视图函数的编写方式
    # 函数内生成forms对象,返回给前端页面
    def home_func(request):
        # 1、生成forms对象
        form_obj = My_modelsform()
        # 2、判断请求方式
        if request.method == 'POST':
            # 3、如果是POST请求,直接获取用户大字典,并将字典内数据传入forms类生成新的forms对象
            form_obj = My_modelsform(request.POST)
            # 4、将新的forms对象传入前端
        return render(request, 'homepage.html', locals())

三、django中间件

简介

  • 客户端信息在经过web协议后进入django框架,中间件类似与保安,会对这些信息进行处理、判断

  • 中间件主要可以用于:网站访问频率的校验 用户权限的校验等全局类型的功能需求

  • Django默认一共有七个中间件,同时还支持自定义中间件

查看中间件

  • 可以在settings.py文件中的MIDDLEWARE中查看中间件
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
     'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

1、自定义中间件

# 1、在项目文件中创建存储中间件的py文件
	My_middleware
      |---My_middleware.py
        
# 2、参考Django自带中间件代码的编写方式进行编写
    import re
    from django.conf import settings
    from django.http import HttpResponsePermanentRedirect
    from django.utils.deprecation import MiddlewareMixin


    class My_midd01(MiddlewareMixin):
        pass

# 3、观察Django自带中间件,发现每个中间件中都含有两个固定功能:
	def process_request(self, request):pass
	def process_response(self, request, response):pass


# 4、在自己编写的中间中添加这两个功能函数
	import re
    from django.conf import settings
    from django.http import HttpResponsePermanentRedirect
    from django.utils.deprecation import MiddlewareMixin


    class My_midd01(MiddlewareMixin):
        def process_request(self, request):
            print('request01')
    
    
    	  def process_response(self, request, response):
            print('response01')

 # 5、模拟客户端发送消息,发现:
	process_request:接收客户端信息是会调用该功能函数
	process_response:返回客户端信息时会调用该功能函数

总结

django默认有七个中间件 并且还支持用户自定义中间件
中间件主要可以用于:网站访问频率的校验 用户权限的校验等全局类型的功能需求
  
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

如何自定义中间件
	1.创建存储自定义中间件代码的py文件或者目录(如果中间件很多)
	2.参考自带中间件的代码编写类并继承
 	3.在类中编写五个可以自定义的方法
    	需要掌握的
        	  process_request
            	1.请求来的时候会从上往下依次经过每一个注册了的中间件里面的该方法 如果没有则直接跳过
            	2.如果该方法自己返回了HttpResponse对象那么不再往后执行而是直接原路返回
 				process_response
             	1.响应走的时候会从下往上依次经过每一个注册了的中间件里面的该方法 如果没有则直接跳过
             	2.该方法有两个先request和response 形参response指代的就是后端想要返回给前端浏览器的数据 该方法必须返回该形参 也可以替换
             '''如果在执行process_request方法的时候直接返回了HttpResponse对象那么会原路返回执行process_response 不是执行所有'''
       需要了解的
           	 process_view
            process_exception
            process_template_response
	4.一定在配置文件中注册中间件才可以生效