Django框架全面讲解二

Django框架全面讲解二
七、中间件(MiddleWare)

django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。

在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,如下图

img

中间件中可以定义五个方法,分别是:

  • process_request(self,request)
  • process_view(self, request, callback, callback_args, callback_kwargs)
  • process_template_response(self,request,response)
  • process_exception(self, request, exception)
  • process_response(self, request, response

分析源码得知前二个方法是从前往后执行的,后三个方法是从后往前执行的

img

所以前两个方法是请求进来的,后三个方法是请求出去的

一张图告诉你中间件的运行流程

img

自定义中间件

1、创建中间件类

class Middle_Test(object):
       
    def process_request(self,request):
        pass
    def process_view(self, request, callback, callback_args, callback_kwargs):
        1
        pass
    def process_exception(self, request, exception):
        pass
    def process_response(self, request, response):
        return response

2、注册中间件

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'sparks.middleware.auth.Middle_Test',
)
八、 Form
1.使用 forms 模块生成表单,主要处理GET请求
	1.forms模块的作用
		通过forms模块,允许将表单与class结合(表单与实体类结合),允许通过class生成表单
	2.使用forms模块
		1.在应用中创建 forms.py 文件
		2.导入forms模块
			from django import forms
		3.创建class,一个class对应生成一个表单
			class ClassName(forms.Form):
				pass
		4.创建属性
			一个属性对应到表单中生成一个控件
	3.在模板中解析 form 对象
		1.注意
			在模板中,需要:
				1.自定义 <form></form>
				2.自定义 提交按钮
		2.处理方法
			1.在 views 中创建 form 的对象并发送到模板上
				form = RemarkForm()
				return render(request,'xxx.html',locals())
			2.在模板中进行解析
				1.手动解析
					{% for field in form %}
						{{field}} :
							表示的就是form对象中的一个独立属性
							表示的也就是一个独立的控件
						{{field.label}}:
							表示的是控件中的label的值
					{% endfor %}
				2.自动解析
					1.{{form.as_p}}
						将form对象中的每个属性使用p标记包裹起来再显示
					2.{{form.as_ul}}
						将form对象中的每个属性使用li标记包裹起来,再显示
						注意:必须手动提供<ol><ul>
					3.{{form.as_table}}
						将form对象中的每个属性用tr标记包裹起来,再显示
						注意:必须手动提供<table>

2.通过 forms.Form 获取表单数据 - POST
    1.通过 forms.Form 的构造函数来接收post数据
    	form = RemarkForm(request.POST)
    2.必须使form通过验证后再获取数据
    	form.is_valid()
    		返回True:提交的数据以及表单已通过所有的验证,允许取值
    		返回False:未通过验证,则不能正常取值
    3.获取表单中的数据
    	通过 form.cleaned_data 来获取提交的数据

form.py

from django import forms

#声明ChoiceField要用到的数据
TOPIC_CHOICE = (
    ('1', '好评'),
    ('2', '中评'),
    ('3', '差评'),
)


class RemarkForm(forms.Form):
    #评论标题
    # forms.CharField() - 文本框
    # label : 控件前的文本标签
    subject = forms.CharField(label='标题')
    #电子邮箱
    # forms.EmailField() - Email框
    # label : 控件前的文本标签
    email = forms.EmailField(label='邮箱')
    #品论内容
    # widget=Textarea : 将当前的单行文本框变为多行文本域
    message = forms.CharField(label='内容', widget=forms.Textarea)
    #品论级别
    # forms.ChoiceField() - 下拉列表框
    # choices : 表示当前下拉列表框中的数据,取值为元组或列表
    topic = forms.ChoiceField(label='级别', choices=TOPIC_CHOICE)
    #是否保存-复选框
    isSaved = forms.BooleanField(label='是否保存')

views.py

def form_register(request):
    if request.method == 'GET':
        form = RegisterForm()
        return render(request,'07-form-register.html',locals())
    else:
        # 将request.POST中的数据提交给RegisterForm()
        form = RegisterForm(request.POST)
        # 将数据通过验证
        if form.is_valid():
        # 验证过后获取数据并保存进数据库
        	au = Author(**form.cleaned_data)
        	au.save()
        	return HttpResponse("Register OK")

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        #id_subject{
        border:none;
        border-bottom:1px solid #000;
        outline:none;
        }
    </style>
</head>
<body>
      {% comment '手动解析' %}
    <form action="/06-form/" method="post">
      {% csrf_token %}
      {% for field in form %}
        <p>
          {{ field.label }}:{{ field }}
        </p>
      {% endfor %}
      <p>
        <input type="submit">
      </p>
    </form>
    {% endcomment %}

    {% comment '自动解析- {{ form.as_p }}' %}
    <form action="/06-form/" method="post">
      {{ form.as_p }}
      <p>
        <input type="submit">
      </p>
    </form>
    {% endcomment %}  
    
</body>
1.使用 forms 模块
	2.forms模块的高级处理
		将 Models 和 Forms 结合到一起使用
		1.在 forms.py 中创建 class ,继承自 forms.ModelForm
		2.创建内部类Meta,去关联 Model
			1.model : 指定要关联的实体类
			2.fields : 指定从Model中取哪些字段生成控件
				1.取值 "__all__",表示全部属性都要生成控件
				2.取值 列表,声明允许生成控件的属性名
			3.labels : 指定每个属性所关联的label,取值为字典
				labels = {
					'属性名':'label文本',
					'属性名':'label文本',
				}
	3.内置小部件 - widget
		1.什么是小部件
			小部件,表示的就是生成到网页上的控件类型以及其他的html属性
		2.常用小部件类型
			1.TextInput : type='text'
			2.PasswordInput : type='password'
			3.NumberInput : type='number'
			4.EmailInput : type='email'
			5.URLInput : type='url'
			6.HiddenInput : type='hidden'
			7.CheckboxInput : type='checkbox'
			8.Textarea : <textarea></textarea>
			9.Select : <select></select>
		3.小部件的使用
			1.继承自 forms.Form 类
				1.基本版
					只指定控件的类型
					class RemarkForm(forms.Form):
						属性 = forms.CharField(
							label='文本',
							widget=forms.小部件类型
						)
				2.高级版
					指定控件类型的基础上还允许设置一些相关的HTML属性到控件上
					属性 = forms.CharField(
						label = '文本',
						widget = forms.小部件类型(
							attrs = {
								'html属性名':'属性值',
								'html属性名':'属性值',
							}
						)
					)
			2.继承自 forms.ModelForm 类
				class XXXForm(forms.ModelForm):
					class Meta:
						model = xxxx
						fields = "__all__"[]
						labels = {
							'属性1':'标签1',
						}
						#指定小部件
						widgets = {
							"属性1":forms.小部件类型(
								attrs = {
									'属性':'值',
								}
							),
						}

form.py

class WidgetForm2(forms.ModelForm):
    class Meta:
        #指定关联的实体
        model = Author
        #指定要显示的字段
        fields = ['name','age','email']
        #指定字段对应的标签
        labels = {
        'name':'用户姓名',
        'age':'用户年龄',
        'email':'用户邮箱',
        }
        #指定字段对应的小部件
        widgets = {
        'age':forms.NumberInput(
            attrs = {
            'placeholder':'请输入年龄',
            'class':'form-control',
            }
        ),
        'email':forms.EmailInput(
            attrs = {
            'placeholder':'请输入您的电子邮箱',
            'class':'form-control',
            }
        )
    }

views.py

def widget2_views(request):
    if request.method == 'GET':
        form = WidgetForm2()
        return render(request,'08-widget1.html',locals())
    else:
		# 将request.POST中的数据提交给RegisterForm()
        form = RegisterForm(request.POST)
        # 将数据通过验证
        if form.is_valid():
        # 验证过后获取数据并保存进数据库
        	au = Author(**form.cleaned_data)
        	au.save()
        	return HttpResponse("Register OK")

html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
    input.form-control{
    border:1px solid #000;
    width:300px;
    height:30px;
    box-sizing:border-box;
    padding:3px 10px;
    outline:none;
    }
</style>
</head>
<body>
    <form action="/09-widget2">
        {{ form.as_p }}
    </form>
</body>
</html>
九、 认证系统(auth)

auth模块是Django提供的标准权限管理系统,可以提供用户身份认证, 用户组管理,并且可以和admin模块配合使用.

在INSTALLED_APPS中添加’django.contrib.auth’使用该APP, auth模块默认启用.

新建用户

from django.contrib.auth.models import User

user = User.objects.create_user(username, email, password)
user.save()

# 不存储用户密码明文而是存储一个Hash值

认证用户

from django.contrib.auth import authenticate

user = authenticate(username=username, password=password)

# 认证用户的密码是否有效, 若有效则返回代表该用户的user对象, 若无效则返回None.
# 该方法不检查is_active标志位.

修改密码:

user.set_password(new_password)

# 以下实例为先认证通过后才可以修改密码
user = auth.authenticate(username=username, password=old_password)
if user is not None:
    user.set_password(new_password)
    user.save()

登录

from django.contrib.auth import login

# login向session中添加SESSION_KEY, 便于对用户进行跟踪:
'login(request, user)'

# login不进行认证,也不检查is_active标志位
# 实例
user = authenticate(username=username, password=password)
if user is not None:
    if user.is_active:
        login(request, user)

退出登录

# logout会移除request中的user信息, 并刷新session

from django.contrib.auth import logout

def logout_view(request):
    logout(request)

只允许登录的用户访问

@login_required装饰器装饰的view函数会先通过session key检查是否登录, 已登录用户可以正常的执行操作, 未登录用户将被重定向到login_url指定的位置,若未指定login_url参数, 则重定向到settings.LOGIN_URL

from django.contrib.auth.decorators import login_required

@login_required(login_url='/accounts/login/')
def userinfo(request):
    ...

# settings 配置
LOGIN_URL = '/index/'
# views
@login_required
def userinfo(request):
    ...
十、 跨站请求伪造(csrf)

django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。

全局:

中间件 django.middleware.csrf.CsrfViewMiddleware

局部:

  • @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
  • @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

注:from django.views.decorators.csrf import csrf_exempt,csrf_protec

应用

1、普通表单

# veiw中设置返回值:
return render(request, 'xxx.html', data)
   
# html中设置Token:
{% csrf_token %}
十一、2.cookies 和 session
2.cookies 和 session
	1.cookies
		1.django 中使用 cookies
			1.设置cookies的值(将数据保存到客户端)
				语法:
					响应对象.set_cookie(key,value,expires)
					key:cookie的名字
					value:cookie的值
					expires:保存时间,以s为单位
				1.不使用模板
					resp = HttpResponse('响应给客户端的一句话')
					resp.set_cookie(key,value,expires)
					return resp
				2.使用模板
					resp = render(request,'xxx.html',locals())
					resp.set_cookie(key,value,expires)
					return resp
				3.使用重定向
					resp = redirect('/地址/')
					resp.set_cookie(key,value,expires)
					return resp
			2.获取cookies的值
				伴随着请求对象到达服务器之后再获取cookie的值
				request.COOKIES:封装了当前访问站点下的所有的cookie的信息
			3.删除cookie的值
				通过响应对象通知客户端删除数据
				resp.delete_cookie(key)
			
	2.session
		1.设置 session 的值
			request.session['key'] =2.获取 session 的值
			value = request.session['key']
			value = request.session.get('key')
		3.删除 session 的值
			del request.session['key']
		4.有关 session 的配置
			在 settings.py 中,有关session的设置
			1.SESSION_COOKIE_AGE
				作用:设置sessionID在cookies中的存活时间
				ex:
					SESSION_COOKIE_AGE=60*30
			2.SESSION_EXPIRE_AT_BROWSER_CLOSE
				作用:设置浏览器关闭时则清除服务器上对应的session空间

				ex:
					SESSION_EXPIRE_AT_BROWSER_CLOSE = True

十二、Session

Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:

  • 数据库(默认)
  • 缓存
  • 文件
  • 缓存+数据库
  • 加密cookie

1.数据库Session

Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
 
a. 配置 settings.py
 
    SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)
     
    SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在浏览器上														时的key,即:sessionid=随机字符串(默认)
    SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路径(默认)
    SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默认)
    SESSION_COOKIE_SECURE = False                            # 是否Https传输cookie(默认)
    SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http传输(默认)
    SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默认)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)
    SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)
 
 
 
b. 使用
 
    def index(request):
        # 获取、设置、删除Session中数据
        request.session['k1']
        request.session.get('k1',None)
        request.session['k1'] = 123
        request.session.setdefault('k1',123) # 存在则不设置
        del request.session['k1']
 
        # 所有 键、值、键值对
        request.session.keys()
        request.session.values()
        request.session.items()
        request.session.iterkeys()
        request.session.itervalues()
        request.session.iteritems()
 
 
        # 用户session的随机字符串
        request.session.session_key
 
        # 将所有Session失效日期小于当前日期的数据删除
        request.session.clear_expired()
 
        # 检查 用户session的随机字符串 在数据库中是否
        request.session.exists("session_key")
 
        # 删除当前用户的所有Session数据
        request.session.delete("session_key")
 
        ...

2、缓存Session

a. 配置 settings.py
 
    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
    SESSION_CACHE_ALIAS = 'default'                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
 
 
    SESSION_COOKIE_NAME = "sessionid"                        # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
    SESSION_COOKIE_PATH = "/"                                # Session的cookie保存的路径
    SESSION_COOKIE_DOMAIN = None                              # Session的cookie保存的域名
    SESSION_COOKIE_SECURE = False                             # 是否Https传输cookie
    SESSION_COOKIE_HTTPONLY = True                            # 是否Session的cookie只支持http传输
    SESSION_COOKIE_AGE = 1209600                              # Session的cookie失效日期(2周)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                   # 是否关闭浏览器使得Session过期
    SESSION_SAVE_EVERY_REQUEST = False                        # 是否每次请求都保存Session,默认修改之后才保存
 
 
 
b. 使用
 
    同上

3、文件Session

a. 配置 settings.py
 
    SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
    SESSION_FILE_PATH = None                                    # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()                                                            # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T
 
 
    SESSION_COOKIE_NAME = "sessionid"                          # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
    SESSION_COOKIE_PATH = "/"                                  # Session的cookie保存的路径
    SESSION_COOKIE_DOMAIN = None                                # Session的cookie保存的域名
    SESSION_COOKIE_SECURE = False                               # 是否Https传输cookie
    SESSION_COOKIE_HTTPONLY = True                              # 是否Session的cookie只支持http传输
    SESSION_COOKIE_AGE = 1209600                                # Session的cookie失效日期(2周)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                     # 是否关闭浏览器使得Session过期
    SESSION_SAVE_EVERY_REQUEST = False                          # 是否每次请求都保存Session,默认修改之后才保存
 
b. 使用
 
    同上

4、缓存 + 数据库 Session

数据库用于做持久化,缓存用于提高效率
 
a. 配置 settings.py
 
    SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎
 
b. 使用
 
    同上

5、加密cookie Session

a. 配置 settings.py
     
    SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎
 
b. 使用
 
    同上
十三、缓存

由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。

Django中提供了6种缓存方式:

  • 开发调试
  • 内存
  • 文件
  • 数据库
  • Memcache缓存(python-memcached模块)
  • Memcache缓存(pylibmc模块)

和数据库类似,缓存的具体操作都是一样的,使用不同的方式只需要将配置改掉即可

1、配置

a、开发调试

# 此为开始调试用,实际内部不做任何操作
    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.dummy.DummyCache',     # 引擎
                'TIMEOUT': 300,                                               # 缓存超时时间(默认300,None表示永不过期,0表示立即过期)
                'OPTIONS':{
                    'MAX_ENTRIES': 300,                                       # 最大缓存个数(默认300)
                    'CULL_FREQUENCY': 3,                                      # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
                },
                'KEY_PREFIX': '',                                             # 缓存key的前缀(默认空)
                'VERSION': 1,                                                 # 缓存key的版本(默认1)
                'KEY_FUNCTION' 函数名                                          # 生成key的函数(默认函数会生成为:【前缀:版本:key】)
            }
        }


    # 自定义key
    def default_key_func(key, key_prefix, version):
        """
        Default function to generate keys.

        Constructs the key used by all other methods. By default it prepends
        the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
        function with custom key making behavior.
        """
        return '%s:%s:%s' % (key_prefix, version, key)

    def get_key_func(key_func):
        """
        Function to decide which key function to use.

        Defaults to ``default_key_func``.
        """
        if key_func is not None:
            if callable(key_func):
                return key_func
            else:
                return import_string(key_func)
        return default_key_func

b、内存

# 此缓存将内容保存至内存的变量中
    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
                'LOCATION': 'unique-snowflake',
            }
        }

    # 注:其他配置同开发调试版本

c、文件

# 此缓存将内容保存至文件
    # 配置:

        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
                'LOCATION': '/var/tmp/django_cache',
            }
        }
    # 注:其他配置同开发调试版本

d、数据库

# 此缓存将内容保存至数据库

    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
                'LOCATION': 'my_cache_table', # 数据库表
            }
        }

    # 注:执行创建表命令 python manage.py createcachetable

e、Memcache缓存(python-memcached模块)

# 此缓存使用python-memcached模块连接memcache

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': '127.0.0.1:11211',
        }
    }

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': 'unix:/tmp/memcached.sock',
        }
    }   

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': [
                '172.19.26.240:11211',
                '172.19.26.242:11211',
            ]
        }
    }

f、Memcache缓存(pylibmc模块)

# 此缓存使用pylibmc模块连接memcache
    
    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': '127.0.0.1:11211',
        }
    }

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': '/tmp/memcached.sock',
        }
    }   

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': [
                '172.19.26.240:11211',
                '172.19.26.242:11211',
            ]
        }
    }

2、应用

a. 全站使用

使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存

    MIDDLEWARE = [
        'django.middleware.cache.UpdateCacheMiddleware',
        # 其他中间件...
        'django.middleware.cache.FetchFromCacheMiddleware',
    ]

    CACHE_MIDDLEWARE_ALIAS = ""
    CACHE_MIDDLEWARE_SECONDS = ""
    CACHE_MIDDLEWARE_KEY_PREFIX = ""

b. 单独视图缓存

方式一:
        from django.views.decorators.cache import cache_page

        @cache_page(60 * 15)
        def my_view(request):
            ...

    方式二:
        from django.views.decorators.cache import cache_page

        urlpatterns = [
            url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
        ]

c、局部视图使用

a. 引入TemplateTag

        {% load cache %}

    b. 使用缓存

        {% cache 5000 缓存key %}
            缓存内容
        {% endcache %}

注:如果出现多个url匹配同一个view函数的情况,缓存机制会根据每一个不同的url做单独的缓存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值