Python学习之路---Django框架-01

Django框架简介

  • Django框架的作用:简便、快速的开发数据库驱动的网站
  • Django框架的特点:1.重量级框架  2.MVT设计模式

MVT设计模式

  • 核心思想:分工,解耦
    让不同代码块之间降低耦合,增强代码的可扩展性和可移植性
  • 传统MVC模式
    M(Model):主要封装对数据库层的访问,对数据库中的数据进行增、删、查、改操作
    V(View):用于封装结果,生成页面展示的html内容
    C(Controller):用于接收请求,处理业务逻辑,与Model和View交互,返回结果
  • Django使用MVT模式
    M(Model):负责与数据库交互,进行数据处理,与MVC中的M功能相同
    V(View):用于接收请求,进行业务处理,返回应答,与MVC中的C功能相同
    T(Template):负责封装构造要返回的html,与MVC中的V功能相同

Django的搭建

  • 创建虚拟环境

    mkvirtualenv 虚拟环境名 -p python3.6
    

    python版本可按具体需求而定

  • 往虚拟环境中安装Django包

    pip install django==2.2.5
    

    django版本可按需求而定,通常安装python版本对应的django版本

  • 创建一个Django工程

    django-admin startproject 工程名
    

    此时可以用tree命令查看工程文件:
    .
    └── demo
       ├── demo
       │  ├── init.py
       │   ├── settings.py
       │  ├── urls.py
       │   └── wsgi.py
       └── manage.py
    其中:
    __init__.py:项目初始化文件
    settings.py:项目的整体配置文件
    urls.py:项目的URL配置文件
    wsgi.py:项目与WSGI兼容的Web服务器入口
    manage.py:项目管理文件,用于管理项目

  • 使用开发服务器运行项目

    python manage.py runserver
    

    服务器运行后,在浏览器中输入“127.0.0.1:8000”即可看到原始页面

  • 创建子应用

    python manage.py startapp 子应用名
    

    这时候我们通过tree命令查看工程文件,新增了以下文件:
    └── users
       ├── __init__.py
       ├── admin.py
       ├── apps.py
       ├── models.py
       ├── migrations
        │   └──__init__.py
       ├── tests.py
       └── views.py
    其中:
    admin.py:与网站的后台管理站点配置相关
    apps.py:用于配置当前子应用的相关信息
    migrations:目录用于存放数据库迁移历史文件
    model.py:用于保存数据库模型类
    test.py:用于开发测试用例,编写单元测试
    views.py:用于编写Web应用视图
    创建出来的子应用需要在项目工程的settings.py文件中进行配置才可以使用,我们需要在demo目录下的settings.py文件的INSTALLED_APPS中添加子应用模块:'users.apps.UsersConfig',注意各元素之间以逗号隔开

  • 创建视图
    在子应用模块的views.py文件中编写视图代码

    from django.http import HttpResponse
    
    def index(request):
    	pass
    	return HttpReponse("响应体")
    
  • 创建子路由
    1)在子应用模块中新建一个urls.py文件保存该应用的路由,该路由被称为子路由
    2)在users/urls.py文件中定义子路由信息:

    from django.conf.urls import re_path
    from . import views
    
    urlpatterns = [
    	re_path(r"^index/$", views.index),
    ]
    

    3)在工程总路由demo/urls.py中添加数据:

    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
    	path("admin/", admin.site.urls),
    	path(r"users/", include("users.urls)),
    ]
    

    "users/"代表子路由以/users/开头
    使用include将子应用users里的路由文件包含到总路由中

  • 关于demo/settings.py文件中的几个重要配置
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    获取到的 BASE_DIR 其实就是当前项目的根目录(绝对路径)

    DEBUG = True
    设置是否为调试模式,创建工程后初始值为True,项目真正部署上线时要修改成False
    作用:Django程序出现异常时,在前端显示详细的错误追踪信息。

    LANGUAGE_CODE = 'en-us' # 语言
    TIME_ZONE = 'UTC' # 时区

路由要点

  • url的构成
    eg:http://127.0.0.1:80/users/index/?a=1&b=2&c=3#box
      协议 :// 域名(ip):端口 / 路由 /?查询字符串 #锚点

  • 路由定义位置
    总路由:位于项目的同名文件夹下的urls.py文件中
    子路由:位于每个子应用下面的urls.py文件中

  • 路由解析顺序:先总后子,从上至下

  • 路由设置的正则表达式要^开头$结尾,否则可能出现屏蔽效应

  • 路由命名

    from django.conf.urls import re_path
    from . import views
    
    app_name = 'user'
    
    urlpatterns = [
    	re_path(r'^index/$', views.index, name='index'),
    	re_path(r'^say', views.say, name='say'),
    ]
    
  • reverse 反解析

    from django.urls import reverse  # 注意导包路径
    
    def index(request):
    	# 我们在index函数中获取say函数的路径
    	url = reverse('user:say')
    	print(url)     # /users/say
    
    	# 或者获取本函数的路径: 
    	url1 = reverse('user:index')
    	print(url1)    # /users/index
    
    	return HttpResponse("hello the world!")
    
    def say(request):
    	return HttpResponse('say')
    

    反解析可以通过自己为路由取的名字反向得到其路径

请求

  • QueryDict对象:Django中的一种特殊类型的字典,可以存储一对一、一对多类型的数据。这个对象一般涌来存储浏览器传递过来的参数。

  • 获取QueryDict中的数据:
    获取一个值:QueryDict.get(key) 获取所有值的最后一个
    获取多个值:QueryDict.getlist(key) 获取key对应的所有值,以列表形式返回

  • 前端传参的四种方式:
    1)查询字符串传参:利用url中的?后面的查询字符串部分进行传参
      可以通过request.GET属性获取,这个方法返回QueryDict对象

    // 前端发送请求: 
    $.ajax({
    	url:'http://127.0.0.1:8000/reqresp/qs/?a=1&b=2&a=3',
    	type:'get',
    	dataType:'json'
    })
    .done(function(data){
    	console.log(data)     // 打印: OK
    })
    .fail(function(error){
    	console.log(error)
    })
    
    # python 部分接收发送的参数并打印: 
    # 视图函数
    def qs(request):
    	# 获取查询字符串参数
    	a = request.GET.get('a')
    	b = request.GET.get('b')
    	alist = request.GET.getlist('a')
    	print(a)  # 3
    	print(b)  # 2
    	print(alist)  # ['1', '3']
    	# 返回响应对象
    	return HttpResponse('OK')
    

      需要注意的是,查询字符串不区分请求方式,即使客户端发送的是POST请求也可以通过request.GET获取请求中的查询字符串数据

    2)路径传参:把参数伪装成路径, 传递到后端
      在定义路由 URL 时,可以使用正则表达式提取参数的方法从 URL 中获取请求参数,Django 会将提取的未命名参数按定义顺序传递到视图的传入参数中。
      除了未命名参数,我们可以对参数进行命名,这样能保证参数传递不会乱
      命名参数子路由:

    re_path(r'^weather/(?P<city>[a-z]+)/(?P<year>\d{4})/$', views.weather),
    

      对应的视图部分:

    def weather(request, year, city):
      	'''定义weather函数, 接收路径参数'''
      	print('city=%s' % city)
      	print('year=%s' % year)
      	return HttpResponse('OK')
    

    3)请求体传参
      Django 默认开启了 CSRF 防护,会对上述请求方式进行 CSRF 防护验证,在测试时可以关闭 CSRF 防护机制,方法为在 settings.py 文件中注释掉 CSRF 中间件
      (1) 表单类型传参
        使用request.POST获取QueryDict类型表单参数
        使用 QueryDict 的 get( ) 和 getlist( ) 函数, 获取数据
      (2) 非表单类型传参
        若前端传递的是 json 类型的数据, 可以通过 request.body 类获取
        获取到的数据是 bytes 类型, 所以我们需要将其解码为 str 类型
        bytes 转为 str 后, 可以调用 json.loads( ) 函数转化为dict类型

    4)请求头传参
      通过 request.META 属性获取请求对象的所有请求头信息,dict类型
      需要注意的是,从 request.META 中获取数据时, key 值需要大写

响应

  • HttpResponse
    1)导入方式

    from django.http import HttpResponse
    

    2)定义形式

    HttpResponse(content,content_type,status)
    

    其中:
      content:响应体
      content_type:响应体数据类型
      status:状态码

    def demo_response(request):
    	str = '{"name": "python"}'
    	return HttpResponse(str, content_type="application/json", status=400)
    

    3)向响应头添加自定义的键值对

    response = HttpResponse()
    response['name'] = 'Python'
    

    4)HttpResponse的子类
      使用HttpResponse子类可以免去设置状态码,但用前记得导入对应的包

      HttpResponseRedirect 301
      HttpResponsePermanentRedirect 302
      HttpResponseNotModified 304
      HttpResponseBadRequest 400
      HttpResponseNotFound 404
      HttpResponseForbidden 403
      HttpResponseNotAllowed 405
      HttpResponseGone 410
      HttpResponseServerError 500
    
  • JsonResponse
    1)作用
      (1)自动将数据转换为 json字符串
      (2)自动设置响应头 Content-Type 为 application/json
    2)使用方法
      导包后直接调用即可

    from django.http import JsonResponse
    def demo_view(request):
    	dict = {
      	'city': 'shenzhen', 
      	'skill': 'python'
    	}
    	return JsonResponse(dict)
    
  • redirect 重定向
    1)作用:实现页面跳转
    2)使用方法
      redirect('想要跳转的路径')

    from django.shortcuts import redirect
    def view1(request):
    	return redirect('/xxx/xx/')
    

    3)redirect可以与reverse搭配使用

    def demo_view2(request):
    	url = reverse('user:index')
    	return redirect(url)
    

类视图

  • 什么是类视图?
    Django中,使用类来定义一个视图称为类视图,对应的,以函数定义视图称为函数视图

  • 类视图的优点
    1)代码可读性强
    2)相对于函数视图具有更高的复用性:类视图可以通过多继承获得父类的功能

  • 类视图的使用

    from django.views import View
    from django.http import HttpResponse
    
    class NewView(View):
    	def get(self, request):
    		...
    		return HttpResponse("")
    	
    	def post(self, request):
    		...
    		return HttpResponse("")
    

    同时,在子路由中要添加如下格式代码:

    	re_path(r'^newview/$', views.NewView.as_view())
    

    注意:与函数视图不同的是,要在类名之后增加as_view()函数,as_view()函数能够根据请求类型(get / post)自动调用类视图中的对应函数

  • as_view()函数的底层实现

    @classonlymethod
    def as_view(cls, **initkwargs):
        ...
        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            return self.dispatch(request, *args, **kwargs)
        ...
        return view
    
    def dispatch(self, request, *args, **kwargs):
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)
    

    实际上,在调用as_view()函数时,会调用其内部的view()函数,view()函数再调用dispatch()函数实现 函数分发 ,决定调用类视图中的哪个函数,而这一切都是自动进行的

  • 类视图使用装饰器

    # 装饰器:
    def my_decorator(func):
    	def wrapper(request, *args, **kwargs):
        	print('请求路径%s' % request.path)
        	return func(request, *args, **kwargs)
    	return wrapper
    # 类视图:
    class NewView(View):
    	def get(self, request):
       		print('调用get方法')
        	return HttpResponse('demoview get')
    	def post(self, request):
        	print('调用post方法')
        	return HttpResponse('demoview post')
    

    1)在子路由配置给函数增加装饰器(不推荐

    urlpatterns = [
    	re_path(r'^demo/$', my_decorate(NewView.as_view()))
    ]
    

    这种装饰方法是间接给类视图的所有函数增加装饰器,既不利于代码的可读性又不灵活,不建议使用
    2)在类视图中装饰
    (1)类内装饰

    from django.utils.decorators import method_decorator
    
    class DemoView(View):
    	@method_decorator(my_decorator)  # 为 get 方法添加装饰器
    	def get(self, request):
        	print('类视图中的 get 方法')
        	return HttpResponse('demoview get')
        	
    	def post(self, request):
        	print('类视图中的 post 方法')
        	return HttpResponse('demoview post')
    

    (2)类外装饰

    # 为特定请求方法添加装饰器
    @method_decorator(my_decorator, name='get')
    class DemoView(View):
    	def get(self, request):
        	print('类视图中的 get 方法')
        	return HttpResponse('demoview get')
    
    	def post(self, request):
        	print('类视图中的 post 方法')
        	return HttpResponse('demoview post')
    
    # 为全部请求方法添加装饰器
    @method_decorator(my_decorator, name='dispatch')
    class DemoView(View):
       def get(self, request):
       	print('类视图中的 get 方法')
       	return HttpResponse('demoview get')
    
       def post(self, request):
       	print('类视图中的 post 方法')
       	return HttpResponse('demoview post')
    

    这种方法需要导入django自带的method_decorator() 装饰器,相较于在子路由装饰具有更好的可读性和灵活性,推荐使用

  • 类视图Mixin扩展类

    def my_decorator_1(func):
    	def wrapper(request, *args, **kwargs):
        	print('请求路径%s' % request.path)
        	return func(request, *args, **kwargs)
    	return wrapper
    	
    def my_decorator_2(func):
    	def wrapper(request, *args, **kwargs):
        	print('请求路径%s' % request.path)
        	return func(request, *args, **kwargs)
    	return wrapper
    
    class FirstMixin(object):
    	""" FirstMixin 扩展类 """
    	@classmethod
    	def as_view(cls, *args, **kwargs):
        	view = super().as_view(*args, **kwargs)
        	view = my_decorator_1(view)
        	return view
    
    class SecondMixin(object):
    	""" SecondMixin 扩展类 """ 
     	@classmethod
    	def as_view(cls, *args, **kwargs):
        	view = super().as_view(*args, **kwargs)
        	view = my_decorator_2(view)
        	return view
    
    class NewView(FirstMixin, SecondMixin, View):
    	def get(self, request):
        	print('newview get')
        	return HttpResponse('newview get')
    
    	def post(self, request):
        	print('newview post')
        	return HttpResponse('newview post')
    

    扩展类第一眼看上去好像很复杂,但本质上就是类的继承而已。
    注意:1.扩展类需要继承自object
        2.类视图调用时,需要把View类添加到最后
        3.在Mixin扩展类中,一般会重写as_view()函数,在函数内添加过滤
        4.一个类视图可以继承多个扩展类, 每个扩展类中都可以添加装饰器

中间件

  • 什么是中间件?
    1)Django的中间件是一个轻量级、底层的插件系统,可以介入请求和响应处理过程,修改Django的输入与输出
    2)中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健壮性
    3)我们可以使用中间件在Django视图的不同阶段对输入或输出进行处理

  • 中间件的定义方式
    1)在子应用中新建一个 middleware.py 文件,按以下格式编写中间件函数

    def middleware(request):
    	...
        response = get_response(request)
        ...
        return response
    return middleware
    

    2)在setting.py文件中添加注册中间件

    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',
     	# 添加中间件
    	'users.middleware.my_middleware',  
    ]
    
  • 多个中间件的执行顺序
    在请求视图被处理,中间件由上至下依次执行
    在请求视图被处理,中间件由下至上依次执行

模板

  • 配置
    1)在工程中创建模板目录templates
    2)在settings.py文件中修改TEMPLATES里的APP_DIRS值
      将'APP_DIRS': True改为'DIRS': [os.path.join(BASE_DIR, 'templates')]

  • 定义模板
    在templates目录中新建一个模板文件:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    	<meta charset="UTF-8">
    	<title>Title</title>
    </head>
    <body>
    	<h1>{{ city }}</h1>
    </body>
    </html>
    
  • 渲染模板
    使用方式:render(request, '模板文件名称', 添加给模板的字典类型数据)

    from django.shortcuts import render
    def index(request):
    	context = {'city': '深圳'}
    	return render(request,'index.html',context)
    

Cookie

  • 什么是Cookie?
    Cookie是由服务端生成,保存在客户端的一种数据存储形式,内部以Key-Value形式存储。Value最大为4KB,Cookie保存的数据不安全,Cookie基于域名安全,不同域名的Cookie是不能互相访问的。

  • Cookie的作用:用于保持前后端状态

  • 设置Cookie
    通过HttpResponse对象中的set_cookie方法来设置cookie

    response = HttpResponse()
    response.set_cookie(key,  value,  max_age)
    

    其中:
      key: cookie 中保存信息的名称
      value: cookie 中保存信息时, 名称对应的值部分
      max_age: cookie 中保存信息的有效期, 超过有效期, key-value 失效
    ​   其中 max_age 单位为秒, 默认为 None. 如果设置 None 值, 则关闭浏览器失效.

  • 读取Cookie
    通过HttpRequest对象的COOKIES属性来读取本次携带的cookie值

    value = request.COOKIES.get('key')
    

Session

  • 什么是Session?
    Session 是一种会话控制方式。 由服务端创建,并且保存在服务端的数据存储形式。 内部以 key/value 键值对的形式存储。session 可以保持会话状态,可以存储敏感信息, 内容有些会被加密。一般生成 session 后, 会把 sessionid 传递给 cookie 保存,session 依赖 cookie。

  • Session的作用
    1)在服务器上保存用户状态信息, 以供前端页面访问
    2)因为数据保存在服务器端, 所以可以保存敏感信息, 每次前端发送请求, 可以随时获取对应的信息,保持会话状态

  • Session的特点
    1)依赖 cookies
    2)存储敏感、重要的信息
    3)支持更多字节,存储在Redis中最大可存储512MB
    4)Session 共享:Session利用独立部署的session服务器(集群)统一管理Session,服务器每次读写Session时,都访问Session服务器。

  • Session的机制:
    1)客户端向服务器发起请求,如果服务器需要记录该用户状态,就可以通过Session在服务端将该用户的唯一标识信息存储起来。
      session_key:一个随机的唯一的不重复的字符串
      session_data:用户的唯一标识信息(密文)
    2)然后,服务端会向客户端浏览器颁发一个Cookie。
      该Cookie中包含了Session存储数据时使用的那个session_key
      该Cookie的具体形式为:‘sessionid’: ‘session_key’
    3)当浏览器再次请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。
    4)服务器提取该Cookie中的session_key,再使用它提取session_data。
    5)最后使用session_data来辨认用户状态

  • 设置Session
    在服务端响应时,使用如下格式代码设置Session:

    request.session['key'] = value
    
  • 读取Session

    request.session.get('key', 默认值)
    
  • 操作Session
    1)清除所有Session,在存储中删除value部分

    request.session.clear()
    

    2)清除Session数据,在存储中删除Session的整条数据

    request.session.flush()
    

    3)删除Session中的指定键及值,在存储中只删除某个键及对应的值

    del request.session['key']
    

    4)设置Session的有效期

    request.session.set_expiry(value)
    

    注意:
    (1) 如果value是一个整数,session将在value秒没有活动后过期。
    (2) 如果value为0,那么用户session的Cookie将在用户的浏览器关闭时过期。
    (3) 如果value为None,那么session有效期将采用系统默认值,默认为两周。可以通过在settings.py中设置SESSION_COOKIE_AGE来设置全局默认值。

  • Session的存储位置
    1)默认存储位置:在settings.py的DATABASES配置项指定的SQL数据库中

    SESSION_ENGINE = 'django.contrib.sessions.backends.db'
    

    2)本地缓存

    SESSION_ENGINE='django.contrib.sessions.backends.cache'
    

    3)混合存储

    SESSION_ENGINE='django.contrib.sessions.backends.cached_db'
    

    4)Redis
    要在Redis中存储Session,需要导入django-redis包
    (1)导包
      pip install django-redis
    (2)配置
    在settings.py文件中做如下配置:

    CACHES = {
    	"default": {
        	"BACKEND": "django_redis.cache.RedisCache",
        	"LOCATION": "redis://127.0.0.1:6379/1",
       		"OPTIONS": {
            	"CLIENT_CLASS": "django_redis.client.DefaultClient",
        	}
    	}
    }
    SESSION_ENGINE = "django.contrib.sessions.backends.cache"
    SESSION_CACHE_ALIAS = "default"
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值