Django 框架基础

Django 框架基础

1. Web框架的本质和意义

  • Web 应用程序处理流程

    • 浏览器 -> web服务器 -> web框架
  • Web应用程序的本质

    • 接收并解析HTTP请求,获取具体的请求信息
    • 处理本次HTTP请求,即完成本次请求的业务逻辑处理
    • 构造并返回处理结果 --- HTTP响应
  • Web 程序框架的意义

    • 用于搭建Web应用程序
    • 免去不同Web应用相同代码部分的重要编写,只需要关系Web应用核心的业务逻辑实现

    ![image-20201206184046489](/Users/luojie/Library/Application Support/typora-user-images/image-20201206184046489.png)

2. Django框架介绍

  • 框架介绍

    • Django ,是用python语言写的开源web开发框架,并遵循MVC设计模式
    • Django的主要目的是简便,快速的开发数据库驱动的网站
  • 特点 -- 重量级框架

    • Django框架相比较于Python其他的的Web框架而言是大而全的
    • django提供了原生的众多功能组件,让开发更简便快速
    • 提供项目工程管理的自动化脚本工具
    • 支持ORM以面向对象的形式操作数据库(Object Relation Mapping)
    • 提供了强大的模板引擎,用于渲染页面
    • 提供了文件管理,认证权限,session机制和缓存
  • MVC设计模式说明:

    • MVC 的全拼为 Model-View-Controller
    • M 全拼为Model,主要封装对数据库层的访问,对数据库中的数据进行增,删,改,查操作
    • V 全拼为 View,用于封装结果,生成页面展示的 html内容
    • C 全拼为 Controller,用于接收请求,处理业务逻辑,与Model和View交互,返回结果
    • MVC 的核心思想是 分工 ,解藕,让不同的代码块之间降低耦合,增强代码的可扩展性和可移植性,实现向后兼容
  • Django的MVT设计模式说明

    • MVT 的全拼为 Model-View-Template

    • 核心思想:分工,解耦

    • M 全拼为 Model,与MVC中的M功能相同,负责和数据库交互,进行数据处理

    • V 全拼为 View,与MVC中的C功能相同,接收请求,进行业务处理,返回应答

    • T 全拼为 Template,与MVC中的V功能相同,负责封装构造要返回的html

    • MVT 的核心思想和 MVC 是相同的

      ![image-20201206183858564](/Users/luojie/Library/Application Support/typora-user-images/image-20201206183858564.png)

3. Django学习资料

4. 虚拟环境和pip相关命令

  • 虚拟环境介绍:
    • 实现一台电脑同时运行多种不同python环境的项目
# 安装虚拟环境
pip3 install virtualenv
pip3 install virtualenvwrapper

# 虚拟环境
workon 				进入虚拟环境,查看所有虚拟环境
mkvirtualenv					创建虚拟环境
rmvirtualenv					删除虚拟环境
deactivate						退出虚拟环境

# pip
pip install					安装依赖包
pip uninstall				卸载依赖包
pip list						查看已安装的依赖库
# 问题:pip3安装virtualenvwrapper 和 virtualenv 成功后命令行输入workon和mkvirtualenv 显示 -bash: mkvirtualenv: command not found

# 解决:
配置环境变量
1. 创建目录用来存放虚拟环境
2. 在~/.bashrc 或者 ~/.bash_profile 中添加行:
export WORKON_HOME=$HOME/.virtualenvs
3. 运行
source /usr/local/bin/virtualenvwrapper.sh
4. 同步文件
source ~/.bashrc

# 问题:
设置超级用户admin站点登录: python manage.py createsuperuser
报错:django.db.utils.OperationalError: no such table: auth_user
解决步骤:
1、ctrl + c (停止服务器)
2、py manage.py makemigrations
3、py manage.py migrate
4、py manage.py runserver (启动服务器)
5. python manage.py createsuperuser (设置账号密码)

5. Django 工程创建

  • 注意:在在做此步骤之前要确定虚拟环境已经安装成功并且可以正常进入虚拟环境,在虚拟环境中 pip3 下载 Django 包

  • 创建工程(使用Django框架时,项目工程可以借助django提供的命令帮助我们创建)

    # 创建工程的命令:
    django-admin startproject Django_t
    # 查看
    (Django_test_2) [luojie@06:15:59:~/heima/python]ls
    Django_test_2
    
    # 工程目录解读
    (Django_test_2) [luojie@06:16:47:~/heima/python/Django_test_2]tree
    .
    ├── Django_test_2
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    └── manage.py
    # 与项目同名的目录,此处为 Django_tets_2
    # settings.py 是项目的整体配置文件(重要)
    # urls.py 是项目的URL配置文件
    # wsgi.py 是项目与WSGI兼容的web服务入口(wsgi是服务器与框架间的通信协议)
    # manage.py 是项目管理文件,通过它管理项目(在启动web服务器程序需要使用)
    
    
  • Django提供了一个纯python编写的轻量级web服务器,但仅在开发阶段使用

    # 启动服务器命令如下:不写ip和端口,默认是127.0.0.1:8000
    python manage.py runserver ip:端口
    或:
    python manage.py runserver
    
    # 启动后django默认工作在Debug模式下,如果增加,,删除,修改文件,保存后服务器会自动重启
    
    

6. Django 工程配置文件解读

  • 打开工程配置文件是 settings.py

    • 在配置文件中,下列配置项表示为当前工程的根目录,Django会依次来定位工程内的相关文件,也可以使用该参数来构建文件路径
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    • 调试模式,创建工程后初始值为 True,即默认工作在调试模式下

      • 作用:修改代码文件,程序自动重启

      • django程序出现异常时,可以向前端显示详细的错误追踪信息

      • **注意:部署线上运行的Django不要运行在调试模式下,记得修改DEBUG=False

        # SECURITY WARNING: don't run with debug turned on in production!
        DEBUG = True
        
        
    • 本地语言与时区

      # Internationalization
      # https://docs.djangoproject.com/en/2.2/topics/i18n/
      
      LANGUAGE_CODE = 'zh-hans'    #语言:简体中文
      TIME_ZONE = 'Asia/shanghai'  #亚洲上海
      
      

7. Django子应用

  • 创建子应用的目的

    • 代码复用(分工,解耦)
    • 在开发过程中通常将工程拆分为不同的子功能模块,每个功能模块负责特定功能
    • 功能模块可以在其他的项目中直接复制使用
  • 创建

    • # 命令:
      python manage.py startapp user
      or
      django-admin startapp user
      
      # 实现效果
      (Django_test_2) [luojie@06:59:11:~/heima/python/Django_test_2]python manage.py startapp luojie
      ## 命令运行成功后在工程目录下会生成一个对应的子应用文件夹
      (Django_test_2) [luojie@06:59:34:~/heima/python/Django_test_2]ls
      Django_test_2 db.sqlite3    luojie        manage.py
      
      # 目录说明:创建的子目录luojie下会自动创建一些.py文件,此文件是建立项目子应用时的重复代码,而你只需要关心功能代码逻辑即可
      ├── luojie
      │   ├── __init__.py
      │   ├── admin.py
      │   ├── apps.py
      │   ├── migrations
      │   │   └── __init__.py
      │   ├── models.py
      │   ├── tests.py
      │   └── views.py
      └── manage.py
      
      • admin.py 文件跟网站的后台管理站点配置相关

      • apps.py 文件用于配置当前子应用的相关信息,子应用配置文件

      • migrations 目录用于存放数据库迁移历史文件

      • models.py 文件用户保存数据库模型类

      • tests.py 文件用于开发测试用列,编写单元测试

      • views.py 文件用于编写Web应用视图,负责接收,处理,返回服务器请求逻辑的代码

  • 注册子应用:创建了一个子应用后,要在主工程目录中的配置文件 setting.py 中添加子应用,这样才会找到子应用并使用子应用功能

    """
    创建出来的子应用目录文件虽然被放到了工程项目目录中,但是django工程并不能立即直接使用该子应用,需要注册安装后才能使用。
    在工程配置文件settings.py中,INSTALLED_APPS项保存了工程中已经注册安装的子应用,初始工程中的INSTALLED_APPS如下:
    注册安装一个子应用的方法,即是将子应用的配置信息文件apps.py中的Config类添加到INSTALLED_APPS列表中。
    """
    
    
    # Application definition
    
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'luojie', # 用户模块子应用
    ]
    
    

8. 视图(views)

  • 视图介绍

    • 视图是Django程序中 **处理后端业务逻辑 ** 的地方

    • Django的视图是定义在子应用的 views.py

    • Django的视图分为 函数视图类视图

      视图示例:
      .
      ├── Django_test_2
      │   ├── __init__.py
      │   ├── __pycache__
      │   │   ├── __init__.cpython-38.pyc
      │   │   ├── settings.cpython-38.pyc
      │   │   ├── urls.cpython-38.pyc
      │   │   └── wsgi.cpython-38.pyc
      │   ├── settings.py			# 主应用的配置文件,其中要注册子应用
      │   ├── urls.py			# 主应用中的路由表,其中要包含子应用的路由表地址,指向子应用
      │   └── wsgi.py
      ├── db.sqlite3
      ├── luojie
      │   ├── __init__.py
      │   ├── __pycache__
      │   │   ├── __init__.cpython-38.pyc
      │   │   ├── admin.cpython-38.pyc
      │   │   ├── models.cpython-38.pyc
      │   │   ├── urls.cpython-38.pyc
      │   │   └── views.cpython-38.pyc
      │   ├── admin.py
      │   ├── apps.py
      │   ├── migrations
      │   │   ├── __init__.py
      │   │   └── __pycache__
      │   │       └── __init__.cpython-38.pyc
      │   ├── models.py
      │   ├── tests.py
      │   ├── urls.py					# 子应用的路由表
      │   └── views.py				# 子应用中的视图,存放后段处理请求的逻辑函数
      └── manage.py
      
      ----------------------------------"子应用中的视图 views.py
      from django.shortcuts import render
      from django.http import HttpResponse
      def start(reques):												# 子应用的函数名
          return HttpResponse("假设是一个处理注册功能的请求模块函数")
        
        
      -----------------------------------"子应用的路由模块 urls.py(自建)
      from django.contrib import admin
      from django.urls import path
      from . import views
      urlpatterns = [
          # 网络地址正则表达式
          # path("网络地址正则表达式", 试图函数名)
          path('start', views.start),							# 包含子应用的函数名
      ]
      
      
      ------------------------------"主应用中的路由模块 urls.py
      from django.contrib import admin
      from django.urls import path, include
      urlpatterns = [
          path('admin/', admin.site.urls),
          path("", include("luojie.urls")),				#包含子应用名和子应用路由
      ]
      
      ----------------------------"主应用中配置文件中的子应用注册 settings.py
      # Application definition
      INSTALLED_APPS = [
          'django.contrib.admin',
          'django.contrib.auth',
          'django.contrib.contenttypes',
          'django.contrib.sessions',
          'django.contrib.messages',
          'django.contrib.staticfiles',
          'luojie',
      ]
      
      
  • 自定义中间件注册原则

    • 多个中间件执行的顺序是有规律的 Middleware

      多个中间件注册顺序:
      MIDDLEWARE = [
          'Middleware1',
          'Middleware2',
          'Middleware3',
      ]
      
      请求时:按照顺序由上而下进入中间件
          [1 ---> 2 ---> 3]
      响应时:先进入的中间件后执行完的
          [3 ---> 2 ---> 1]
      
      经验:
          中间件中请求优先的逻辑,中间件一定要放在最前注册
          中间件中响应优先的逻辑,中间件一定要放在最后注册
      
      例子:
          解决前后端分离时请求跨域的问题
          每个请求都要解决跨域的问题,所以需要用到中间件
          而且需要在请求处理时最先处理跨域的问题,所以解决请求跨域时的中间件需要最先注册
      

8.1 函数视图

  • 定义函数视图的方式:views.py

  • 
    1. 函数视图它是一个标准的Python函数。
    2. 函数视图中,第一个参数必须定义:第一个参数为请求对象,用于接收用户发送的请求报文。
    3. 函数视图中,必须返回响应对象:用于构造响应报文,并响应给用户。
    4. 说明:
        请求对象:HttpRequest() 对应的对象
        响应对象:HttpResponse() 对应的对象
        
        
    from django.shortcuts import render
    from django.http import HttpResponse
    def start(reques):		# 子应用的函数名
      """
      	用户注册函数视图
    		:param request: 请求对象,包含了请求报文信息
        :return: 响应对象,用于构造响应报文,并响应给用户
      """
    		# 响应数据
      	return HttpResponse("假设是一个处理注册功能的请求模块函数")
    
  • 访问函数视图 --- 路由

    • 用户如何访问函数视图?

      • 通过网络地址向Django程序发请求,即可访问到函数视图
      • 路由:使用路由匹配请求地址,每匹配成功一个就执行对应的函数视图逻辑
      • 定义路由的方法:path( ), re_path( ), utl( )
      • 用户通过网络地址:http://127.0.0.1:8000/start 访问用户注册视图
    • 注册子路由:在子路由/urls.py 文件中定义路由信息

    • from django.urls import path
      from . import views
      
      # urlpatterns是被Django自动识别的路由列表变量:定义该应用的所有路由信息
      urlpatterns = [
          # 函数视图路由语法:
          # path('网络地址正则表达式', 函数视图名),
      
          # 用户注册:http://127.0.0.1:8000/users/register/
          path('users/register/', views.register),
      ]
      
    • 注册总路由:在工程总路由 '工程同名目录/urls.py' 中包含子应用的路由数据

    • from django.contrib import admin
      from django.urls import path, include
      
      urlpatterns = [
          # 自带的后台管理系统的总路由:可以忽略
          path('admin/', admin.site.urls),
      
          # 总路由包含子路由语法
          # path('网络地址前缀/', include('子应用.urls')),
          # 或者
          # path('', include('子应用.urls')),
      
          # 用户模块:http://127.0.0.1:8000/users/register/
          path('', include('users.urls')),
      ]
      
    • 路由说明:

      • 一个子应用对应一个总路由
      • 总路由中,使用 include( ) 来将 users 子应用 里的所有路由都包含进工程总路由中
    • 路由匹配函数视图逻辑

      路由匹配函数视图逻辑

8.2 类视图

  • 需求:如果一个用户向同一个访问路径发送 GET/POST 请求时如何处理响应?
    • 用户向地址http://127.0.0.1:8000/users/register/发送GET请求,用来获取注册页面。
    • 用户向地址http://127.0.0.1:8000/users/register/发送POST请求,用来实现注册逻辑。
# 类函数实现:
def register(request):
    """
    用户注册函数视图
    :param request: 请求对象,包含了请求报文信息
    :return: 响应对象,用于构造响应报文,并响应给用户
    """
    # 获取请求方法,判断是GET还是POST请求
    if request.method == 'GET':
        # 处理GET请求,返回注册页面
        return HttpResponse('这里假装返回注册页面')
    else:
        # 处理POST请求,实现注册逻辑
        return HttpResponse('这里假装实现注册逻辑')
      
      
 问题:
当遇到视图对应的同一个路径,提供了多种不同HTTP请求方式的支持时,便需要在一个函数中编写不同的业务逻辑,代码可读性与复用性都很差。

定义类视图

  • 类视图的好处:
    • 代码可读性号
    • 类视图相当于函数视图有更高的复用性
  • 作用
    • 为了让一个视图对应的路径提供多种不同HTTP请求方式的支持时,在Django中可以使用类来定义一个视图,称为类视图
1. 类视图它是一个标准的Python类。
2. 类视图需要继承自Django提供的父类视图View。
3. 在类视图中,
    3.1 需要定义跟请求方法同名的函数来对应不同请求方式
    3.2 在请求方法同名的函数中,还必须定义一个接收请求的参数(同函数视图)
    3.3 在请求方法同名的函数中,还必须返回一个响应对象(同函数视图)
  • 【重点】类视图的定义和使用

    • 定义类视图需要继承自Django提供的父类 View

    • 在类视图中分别实现对应的:GET请求,POST请求等方法处理不同业务逻辑

    • from django.views.generic import View
      
      class RegisterView(View):
          """类视图:处理注册"""
      
          def get(self, request):
              """处理GET请求,返回注册页面"""
              return HttpResponse("这里加载注册页面")
      
          def post(self, request):
              """处理POST请求,实现注册逻辑"""
              return HttpResponse('这里实现注册逻辑')
      
    • 配置路由时,使用类视图的 as_view()方法来添加

    • urlpatterns = [
          # 视图函数:注册
          # path('users/register/', views.register),
          # 类视图:注册
          path('users/register/', views.RegisterView.as_view()),
      ]
      

      路由匹配类视图逻辑

8.3 as_view 底层原理理解

  • 路由绑定过程:
    • path("users/register/", views.RegisterView.as_view())
    • as_view() 函数 定义并返回view
    • 本质是: path("users/register/", view)
  • 调用流程
    • view(request)-->dispatch(request)
    • handler = getattr('对象','方法名') --> handler() --> get() or post()

8.4 类视图添加扩展类 Mixin

  • 作用:使用类多继承特性 为类视图补充拓展功能,实现代码复用

  • 方式:在类视图中定义一个父类视图实现某种扩展功能,然后让类继承这个父类,从而实现功能

  • 步骤:

    1.使用面向对象多继承的特性,定义扩展类。 [定义Mixin扩展类]
    2.在父类中定义想要向类视图补充的方法。 [实现拓展功能]
    3.类视图继承这些扩展父类。 [多继承]
    

8.5 路由定义的位置和解析的顺序

  • path he re_path和 url

    • 用法:函数(正则表达式,视图函数)

    • 区别:

      • path() 正则表达式中自动添加开头和结尾(完全匹配路径 ^ 路径 $ )

      • re_path( ), url( ) : 正则表达式中需要自己强制添加开头和结尾限制

      •     path("users/register/", views.RegisterView.as_view()),
            re_path(r"^users/login/$", views.LoginView.as_view()),
            url(r"^users/login/$", views.LoginView.as_view()),
        
      • 如果不定义路径的开头结尾限制,则请求路径会向后扩展任意字符

    • 定义位置:

      • 总路由中: include("")
      • 子应用的路由: path("", views.index)
    • 解析顺序:

      • url patterns列表中以由上至下的顺序查找路由

      • 如果发现规则为include包含,再进入被包含的urls中的urlpatterns列表由上至下的顺序查找路由找

      • 整体顺序:

        ROOT_URLCONF = 'demo.urls' -> 总路由demo.urls -> include -> 子应用的urls

    • 避免出现屏蔽效应

      • 正则表达式匹配造成的路由屏蔽问题
        • re_path 或者 url时使用 ^...$ 限制开头和结尾
        • 建议使用 path 来定义,会自动做限制

9.请求HttpRequest

  • 目的:获取用户发来的参数数据

  • 用户发送请求时携带的参数 后端需要使用时,而又不同的发送参数方式又对应了不同的提取参数的方式

  • 前端传递参数的4种方式:

    • URL中携带查询字符串的方式(query string)

      • 视图中请求方式: request.GET
      • 比如:http://127.0.0.1:8000/?name=wang & age
    • 请求体(body)中携带数据的方式(get方式没有请求体,post请求方式才有)

      • 视图中的请求方式:
        • 表单数据时: request.POST
        • 非表单数据时:request.body
    • URL路径中携带特定数据的方式

      • 在子路由表中de 路由匹配方式:int:age ---> def get (self, request, age)
    • 请求头中携带数据

      • HTTP 请求报文中的请求数据(header)
      • 在请求头中获取传递值时的视图中的请求方式:request.META

9.1 提取查询字符串中的数据

  • 获取请求路径中的查询字符串参数,如:http:// url/?k1=v1 & k2=v2
  • 可以通过 request.GET 属性获取,并返回 QueryDict 类型的对象
    • Request.GET.get("键", 默认值)
    • Request.GET.getlist("键",默认值)
  • 注意:查询字符串不区分请求方式,即假使客户端进行POST方式的请求,依然可以通过request.GET获取请求中的查询字符串数据

示例:

# 子路由
from django.urls import path, re_path
from . import views
urlpatterns = [
    path('querystring/', views.QSPparamView.as_view()),
]

# 视图函数
class QSPparamView(View):
    def get(self, request):
        # 如果浏览器使用查询字符串传递参数,那么后端服务器要使用request中的GET属性获取
        # request.GET 是QueryDict类型的字典对象,
        #       可以使用
        #       1. get('key','默认值')
        #       2. ['key']  两种方式获取属性值
        name = request.GET.get("name", "小明")
        age = request.GET.get("age", "0")

        # 扩展:QueryDict 支持一个key对应多个值
        like = request.GET.getlist("like", [])
        return HttpResponse("获取查询字符串:name : %s    age : %s    like : %s" % (name, age, str(like)))

    def post(self, request):
        # 如果浏览器使用查询字符串传递参数,那么后端服务器要使用request中的GET属性获取
        # request.GET 是QueryDict类型的字典对象,
        #       可以使用
        #       1. get('key','默认值')
        #       2. ['key']  两种方式获取属性值
        name = request.GET.get("name", "小明")
        age = request.GET.get("age", "0")

        # 扩展:QueryDict 支持一个key对应多个值
        like = request.GET.getlist("like", [])
        return HttpResponse("获取查询字符串:name : %s    age : %s    like : %s" % (name, age, str(like)))


9.2 提取请求体中的数据

  • 提取请求体中的额数据也就是body中传递的参数如form表单数据
  • 提取form表单的步骤:
    • 1.Django中关闭CSRF

9.3 提取表单类型的请求数据(Form Data)

9.4 非表单类型请求体数据(Non-From Data): JSON格式

  • 非表单数据的提取就是在浏览器请求时的post请求体中提from表单
    • 提取form表单步骤:
      • 1.Django中关闭CSRF防护
      • 2.request.POST属性获取(QueryDict对象)
    • 注意:request.POST只能获取POST方式请求体表单数据
# 子应用路由
from django.urls import path, re_path
from . import views

urlpatterns = [
    path('fromdata/', views.FormDataParamView.as_view()),
]

# 视图函数
from django.views import View
from django.http import HttpResponse, JsonResponse
import json
class FormDataParamView(View):
    # 注:请求体有数据就一定是post请求
    # 如果浏览器通过请求体发送数据,就使用request.POST属性获取请求体数据
    # request.POST 属性中返回的数据类型也是 QueryDict 类型(字典)

    def post(self, request):
        username = request.POST.get("username", "")
        password = request.POST.get("password", "")

        return HttpResponse("从浏览器获取到的表单格式请求体内容:%s -- %s" % (username, password))
    # 注:request.POST属性只能获取post方法发来的请求体数据,
    # 具有局限性,不能获取其他例如put 等方法发来的数据

    def put(self, request):
        # 如果浏览器发送PUT表单格式的请求体数据,后端服务器可以使用 request.body 属性获取请求体内容
        print(request.body)
        return HttpResponse("获取到表单格式的请求内容:%s" % request.body.decode("utf-8"))

9.5 URL路径传参:提取URL路径中的特定部分数据

9.5.1 用path() 提取请求路径中参数
  • 在子路由表中的path中的第一个参数写正则表达式,也可以使用 Django path中规定的正则表达式关键字来获取 前端传来的URL中携带的符合正则匹配的参数
  • 默认支持的路由转换器:位置在 django.urls.converters.py
'路由转换器:Django默认封装了一些正则表达式,用于在path()中提取路径参数时使用'
DEFAULT_CONVERTERS = {
    'int': IntConverter(), # 匹配正整数,包含0
    'path': PathConverter(), # 匹配任何非空字符串,包含了路径分隔符
    'slug': SlugConverter(), # 匹配字母、数字以及横杠、下划线组成的字符串
    'str': StringConverter(), # 匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
    'uuid': UUIDConverter(), # 匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00
}

示例:

# 思路: 在子路由表中定义正则表达式,符合正则的就跳转到视图中的处理函数
# 步骤1: 定义子路由表,获取url中的数字
from django.urls import path, re_path
from . import views

urlpatterns = [
    path('url_param1/<int:age>/', 			views.UrlParam1View.as_view()),
]

# 步骤2: 定义视图
class UrlParam1View(View):
    # path()提取url路径中参数
    # 例 http://127.0.0.1:8000/88/ 中的88时,可以在路由表中对数字做正则表达式匹配
    # 来获取也可以在path路径后使用/<int:age>/来获取,此时int表示数字类型age要是下列响应函数的形参中用于
    # 接收传参,int 是默认Django实现的正则表达式的别名,age是参数名
    def get(self, request, age):
        return HttpResponse("获取url中特定部分参数:age %s" % age)
'路由中提取路径参数时,使用的关键字,必须跟视图中参数名一致'
  • 在使用默认路由转换器无法满足需求时,可以自定义路由转换器
    • 自定义路由转换器
# 目的:自定义路由转换器实现自己调用并实现路由匹配捕获
# 示例:实现获取前端路径中传到后端的手机号参数

9.5.2 re_path() 提取路径参数
9.5.3 path() 和re_path() 如何选择?

9.6 请求头传参

​ 可以使用 request.META 属性获取请求头headers中的数据, request.META为字典类型

常见的请求头如下:

'注意:Django会将前端发来的请求头中的短横杠(-),自动转换为下面这种下划线的请求头名称,所以在后端获取请求头的数据时就需要按照下列请求头的格式进去取值'

CONTENT_LENGTH – The length of the request body (as a string).
CONTENT_TYPE – The MIME type of the request body.
HTTP_ACCEPT – Acceptable content types for the response.
HTTP_ACCEPT_ENCODING – Acceptable encodings for the response.
HTTP_ACCEPT_LANGUAGE – Acceptable languages for the response.
HTTP_HOST – The HTTP Host header sent by the client.
HTTP_REFERER – The referring page, if any.
HTTP_USER_AGENT – The client’s user-agent string.
QUERY_STRING – The query string, as a single (unparsed) string.
REMOTE_ADDR – The IP address of the client.
REMOTE_HOST – The hostname of the client.
REMOTE_USER – The user authenticated by the Web server, if any.
REQUEST_METHOD – A string such as "GET" or "POST".
SERVER_NAME – The hostname of the server.
SERVER_PORT – The port of the server (as a string).

使用方式如下:

# 子路由写法
from django.urls import path, re_path
from . import views

urlpatterns = [
 path('url_params4/', views.HeadersParamView.as_view()),
]

# 子应用视图,获取请求头部中的值
class HeadersParamView(View):
    def get(self, request ):
        # name = request.META
        name = request.META.get("HTTP_TEST")
        return HttpResponse("获取到请求头信息 %s" % name)

9.7 其他常用HttpRequest对象属性

  • method:一个字符串,表示请求使用的HTTP方法,常用值包括:'GET'、'POST'。
  • FILES:一个类似于字典的对象,包含所有的上传文件。
  • COOKIES:一个字符串,包含了浏览器自动发送的cookie缓存数据。
  • user:请求中认证出来的用户对象。

10.响应HttpResponse

  • 视图在接收请求并处理后,必须返回HttpResponse对象或子对象
  • HttpRequest对象由Django创建,HttpResponse 对象或子对象由开发人员创建
  • 常见的响应方式:
    • HttpResponse( ) : 响应多种数据类型
    • JsonResponse( ) : 响应JSON
    • redirect( ) : 重定向
    • reder( ) : 渲染并响应HTML模版

10.1 HttpResponse

  • 构建响应对象:django.http.HttpResponse

    # 子应用的视图写法:
    class JSONResponseView(View):
        def get(self, request):
            # 写法1: 使用 HttpResponse 构建响应对象
            return HttpResponse(content='itcast python',
            content_type="text/html;charset=utf-8", status=200)
           
            # 写法2: 可为简写
            '因为在HttpResponse 方法中除了返回内容content需要定义,其他属性都有默认值可以自动填充解析'
            return HttpResponse("itcast python")
          
          	# 写法3: 另外一种写法
            response = HttpResponse("itcast python")
            return response
    
    
    # Django提供一系列HttpResponse的子类,可以快速设置状态码:
    
    HttpResponseRedirect 默认响应状态码为 301
    HttpResponsePermanentRedirect 默认响应状态码为 302
    HttpResponseNotModified 默认响应状态码为 304
    HttpResponseBadRequest 默认响应状态码为 400
    HttpResponseNotFound 默认响应状态码为 404
    HttpResponseForbidden 默认响应状态码为 403
    HttpResponseNotAllowed 默认响应状态码为 405
    HttpResponseGone 默认响应状态码为 410
    HttpResponseServerError 默认响应状态码为 500
    
    

10.2 JsonResponse: 响应JSON格式数据

  • 应用场景:在开发功能时前端如果需要JSON格式的数据,后端就需要构造并响应JSON数据
  • Django提供了 JsonResponse 来构造并响应JSON数据
  • JsonResponse 作用:
    • 帮助我们将响应的数据转换为JSON字符串
    • 设置响应Content-Type 为 application/json
示例:
from django.urls import path, re_path
from . import views
urlpatterns = [
path('json_resp/', views.JSONResponseView.as_view()),]

class JSONResponseView(View):
   dict_data = {
              "city" : "beijing",
              "subject": "python",
              "responseCode": "jjjj",
              "responseMessage": "请求成功"
          }

        return JsonResponse(dict_data,content_type="text/html;charset=utf-8")

10.3 redirect() : 重定向

  • 需求:从一个页面跳转到另一个页面
  • 需要用到的函数方法:redirect( )
    • 示例:访问 LoginRedirectView 时,如果其中的登录逻辑处理完成,就将用户重定向到首页
# 子中的写法路由
from django.views import View
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render, redirect, reverse

# 子应用视图中的写法
class IndexView(View):
    def get(self, request):
        return HttpResponse("假装这是个网站首页")

class LoginRedirectView(View):
    """
    请求地址为login_redirect时跳转到首页
    """
    def post(self, request):
        # 查询数据库获取用户名和密码
        # 验证用户名
        # 验证密码
        # 验证成功,说明登录成功,引导到首页
        # ret_url = reverse("request_response: index/")
        return redirect("/index/")
        # return redirect(ret_url)
        
        
 # 子路由写法:在子路由中做路路由重定向实现跳转
from django.urls import path, re_path
from . import views
urlpatterns = [
 path('index/', views.IndexView.as_view(), name='index'),
 path('login_redirect/', views.LoginRedirectView.as_view()),
]

10.4 路由反向解析

  • 路由反向解析是使用路由别名,动态的解析出该路由中的真实地址

  • 路由反响解析起别名的意义:如果登录页面成功之后重定向跳转到首页这个过程中,登录页面的跳转是直接与首页写死的,如果首页路径修改更新了改变,那就会影响到登录界面的跳转;解决这个问题的办法就是在子路由表中给首页路径起别名,再在登录视图函数中将首页路径别名与函数关联,起首页路径随意改变,跳转到该首页的其他页面的重定向不受影响;

  • 定义路由解析的步骤:

    • 总路由定义子路由别名 ---> 子路由定义资源请求路径别名 ---> 子路由视图函数中定义两个别名的连接关系
    • 1.总路由表中,给子应用的总路由起别名
    from django.contrib import admin
    from django.urls import path, include
    from django.urls import register_converter
    
    urlpatterns = [
        # path("", include("request_response.urls")),
        # 1。在总路由中给子应用的路由起别名(方便反向解析)
        path("", include(('request_response.urls', 'request_response'), namespace='request_response_alias'))
    ]
    
    • 2.子路由中,给子应用的子路由起别名
     # 首页路径从index/ 改变到 two_index/ 时,不影响login_redirect/ 到首页的重定向
     path('index/', views.IndexView.as_view(), name='index_alias'),
     path('two_index/', views.IndexView.as_view(), name='index_alias'),
     path('login_redirect/', views.LoginRedirectView.as_view()),
    
    • 3.定义视图函数,在视图函数中要定义总路由别名和子路由别名的对应关系
    class LoginRedirectView(View):
        """
        请求地址为login_redirect时跳转到别名为index_alias的页面
        """
        def post(self, request):
          	""" 
    				场景:查询数据库获取用户名和密码
            验证用户名,验证密码
            验证成功,说明登录成功,引导到首页
          	"""
            # 总路由别名:子路由别名
            # 利用别名重定向的好处是,只要别名不变就可以跳转到同一个的首页
            # ret_url=reverse('总路由别名:子路由别名')
            ret_url = reverse("request_response_alias: index_alias")
            return redirect(ret_url)
          
      	def get(self, request):
          # get方法请求,
          # 请求路径跳转过程:http://127.0.0.1:8000/login_redirect/ ---> http://127.0.0.1:8000/two_index/
            ret_url = reverse("request_response_alias:index_alias")
            return redirect(ret_url)
      
    

11. 中间件Middleware

  • 概念:Django中的中间件事一个轻量级,底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出

  • 中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健壮性,其他的MVC框架也有这个功能

  • 设计思想:

    • 面向切面编程,无侵害式编程
    • 不用直接修改框架源码,就可以达到自己想要的执行结果
  • 在主工程中的配置文件(settings.py)中 ,有默认的中间件

    # 中间件
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        # 为保证非GET请求(POST,PUT,DELETE)可以正常接收,该中间件需要注释掉
        # 'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        'middlewares.TestMiddleware1',
    ]
    
  • 定义中间件的方法:

    • 说明:Django在中间件中预置了六个方法,这六个方法会在不同的阶段自动执行,对输入或输出进行干预
  • 1.初始化方法:启动Django程序,初始化中间件时,自动调用一次,用于确定是否启用当前中间件

    def __init__(self, get_response=None):
      pass
    
  • 2.处理请求前的方法:(重要)在处理每个请求前,自动调用,返回None或HttpResponse对象

    def process_request(self, request):
      pass
    
  • 3.处理视图前的方法:(重要)在处理每个视图前,自动调用,返回None或HttpResponse对象

    def process_view(self, request, view_func, view_args, view_kwargs):
      pass
    
  • 4.处理模版响应前的方法:在处理每个模版响应前,自动调用,返回实现了render方法的响应对象

    def process_template_response(self, request, response):
      pass
    
  • 5.处理响应后的方法:(重要)在每个响应后给客户端之前,自动调用,返回HttpResponse对象

    def process_response(self, request, response):
      pass
    
  • 6.异常处理:当视图抛出异常时,自动调用,返回一个HttpResponse对象

    def process_exception(self, request,exception):
      pass
    
  • 自定义中间件

    • 定义方法:在工程根目录下,新建middleware.py 文件来定义中间件,然后在配置文件settings.pyMIDDLEWARE配置项中注册这个自定义中间件

    • 中间件是一个独立的Python类,可以定义Django提供的六个方法中的一个或多个

    • 在下列自定义中间件例子中,实现了最重要的三个方法

    • 处理请求前 ---> 处理视图前 ---> 返回响应前

      # 定义中间件
      from django.utils.deprecation import MiddlewareMixin
      class TestMiddleware1(MiddlewareMixin):
          # def __init__(self, get_response=None):
          #     print("初始化中间件")
      
          def process_request(self, request):
              print("处理请求前")
      
          def process_view(self, request, view_func, view_args, view_kwargs):
              print("处理视图前")
      
          def process_response(self, request, response):
              print("处理响应后,视图返回被调用后")
              return response
            
            
      # 将自定义的中间件注册到配置文件中 setting.py
      MIDDLEWARE = [
      		...
          'middlewares.TestMiddleware1',
      ]
      
      
  • 中间件执行顺序:当有多个中间件时

  • 规律这里的上下指的是多个中间件在setting.py 配置项中的注册循序

    • 在视图被处理前(输入),中间件由上至下依次执行
    • 在视图被处理后(输出),中间件由下至上依次执行

12. 模型(models)

  • 说明:在Django中要连接数据库操作的实现逻辑是依靠ORM框架来连接,ORM框架会将SQL语句转化为类或者对象供Django中的程序调用;并且另一个角度也可以说ORM框架抹平了不同类型关系数据库的差距,可以通过ORM连接Mysql,Oracle,SQLite等数据库,无需在代码中编写sql语句。

  • ORM框架介绍:

    • O是object,也就是类或者对象的意思,这里的类就是模型类
    • R是relation,也就是关系数据库中数据表的意思
    • M是mapping,也就是映射的意思
  • 在ORM框架中,它帮我们把模型类和数据表进行了一个映射,可以让我们通过模型类及对象就能操作它所对应的数据表中的数据

  • ORM框架它还可以根据我们设计的模型类自动帮我们生成数据库中对应的数据表,省去了建表的过程

    提示

  • Django框架中内嵌了ORM框架,所有在使用Django框架时,我们不需要直接面向数剧库编程

  • 而是定义模型类,通过模型类及对象完成数据表的增删改查操作

ORM框架的作用

  • 以面向对象的思想去操作数据库
  • ORM框架屏蔽了数据库之间的差异

在python虚拟环境中使用Django编程需要在虚拟环境中安装mysqlcliet包来实现连接

12.1 Django中使用ORM框架连接数据库的步骤:

1.第一步:在总工程配置文件中配置数据库

# 总工程/setting.py 	文件中定义数据库
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': '127.0.0.1',
        'PORT': 3306,
        'USER': 'root',
        'PASSWORD': '',
        'NAME': 'django_demo'
    }
}

2.第二步:创建子应用 booktest,并在 models.py 文件中定义模型类

  • 模型类被定义在 子应用/models.py 文件中
  • 模型类必须继承自Model类,位于 django.db.models
from django.db import models

# Create your models here.

# 定义模型类
class BookeInfo(models.Model):
    # 属性 = modeles.类型(选项);选项也是约束
    # verbose_name= 的意思是在Django后台管理站点显示数据库时使用这个定义的中文显示
    btitle = models.CharField(max_length=20, verbose_name="书名")
    bpub_date = models.DateField(verbose_name="发布日期")
    bread = models.IntegerField(default=0, verbose_name="阅读量")
    bcomment = models.IntegerField(default=0, verbose_name="评论量")
    is_delete = models.BooleanField(default=False, verbose_name="逻辑删除")

    class Meta:
        # 自定义库中的表名
        db_table = "tb_books"

    def __str__(self):
        # print 打印当前类的对象时自动执行下面代码,打印书名书来
        return self.btitle
        
# 模型类解释说明:
关于主键:
1.Django会为表创建自动增长的主键列,每个模型只能有一个主键列
2.默认创建的主键列属性为 id ,可以使用 pk 代替,pk全拼primary key
3.如果使用选项设置某属性为主键列后Django不会在创建自动增长的主键列

关于属性命名:
1.不能是python的保留关键字
2.不允许使用连续的下划线,这是有Django的查询方式决定的
3.定义属性时需要指定字段类型,通过字段类型的参数指定选项,语法如下:
		属性 = models.字段类型(选项)
  
关于数据库表名:
1.模型类如果为指明表名,Django默认以 小写app应用名_小写模型类名 为数据库表名
2.但是可以通过模型的元类中的 db_table 自定义数据库表名

关于字段类型:

类型 说明
AutoField 自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性
BooleanField 布尔字段,值为True或False
NullBooleanField 支持Null、True、False三种值
CharField 字符串,参数max_length表示最大字符个数
TextField 大文本字段,一般超过4000个字符时使用
IntegerField 整数
DecimalField 十进制浮点数, 参数max_digits表示总位数, 参数decimal_places表示小数位数
FloatField 浮点数
DateField 日期, 参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为False; 参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为False; 参数auto_now_add和auto_now是相互排斥的,组合将会发生错误
TimeField 时间,参数同DateField
DateTimeField 日期时间,参数同DateField
FileField 上传文件字段
ImageField 继承于FileField,对上传的内容进行校验,确保是有效的图片

关于字段选项:

选项 说明
null 如果为True,表示允许为空,默认值是False
db_column 字段的名称,如果未指定,则使用属性的名称
db_index 若值为True, 则在表中会为此字段创建索引,默认值是False
default 默认
primary_key 若为True,则该字段会成为模型的主键字段,默认值是False,一般作为AutoField的选项使用
unique 如果为True, 这个字段在表中必须有唯一值,默认值是False

关于外键

在设置外键时,需要通过on_delete选项指明主表删除数据时,对于外键引用表数据如何处理,在django.db.models 中包含了可选常量:

  • CASCADE 级联,删除主表数据时连通一起删除外键表中数据
  • PROTECT 保护,通过抛出ProtectedError异常,来阻止删除主表中被外键应用的数据
  • SET_NULL 设置为NULL,仅在该字段null=True允许为null时可用
  • SET_DEFAULT 设置为默认值,仅在该字段设置了默认值时可用
  • SET() 设置为特定值或者调用特定方法
  • DO_NOTHING 不做任何操作,如果数据库前置指明级联性,此选项会抛出IntegrityError异常

3.第三步:迁移模型类建表

在虚拟环境的命令行中执行生成迁移文件名令:

python manage.py makemigrations

4.第四步:将迁移文件同步到数据库中

python manage.py migrate

12.2 数据库增删改查

  • 新增数据:有两种方法

    • 1)save:通过创建模型类对象,模型对象.save()方法保存到数据库中

    • # 新增:方式一
      book = BookInfo()
      book.btitle = '西游记'
      book.bpub_date = '2020-05-18'
      book.bread = 20
      book.bcomment = 30
      book.save()
      
    • 2)create : 通过 模型类.objects.create() 保存

    • # 新增:方式二
      BookInfo.objects.create(
          btitle='三国演义',
          bpub_date='2020-05-20',
          bread=100,
          bcomment=200
      )
      
  • 修改数据:两种方法

      1. save 修改模型类对象的属性,然后执行 save() 方法
    • hero = HeroInfo.objects.get(hname='猪八戒')
      hero.hname = '猪悟能'
      hero.save()
      
    • 2)update:使用模型类.object.filter().update(), 会返回受影响的行数

    • HeroInfo.objects.filter(hname='沙悟净').update(hname='沙僧')
      
  • 删除:两种方法

      1. 模型类对象delete
    • hero = HeroInfo.objects.get(id=13)
      hero.delete()
      
    • 2)模型类.objects.filter().delete()

    • HeroInfo.objects.filter(id=14).delete()
      
  • 查询

原因:HTTP协议是无状态

所有:状态保持有cookie和session两种;大小,存储位置,信息敏感性,工作方式等区别

a[s] ---> b[]
b --> c[hss]
graph TD a --> b

id ;8aaf0708762cb1cf01765a26fe4d0f27

key: cd904c4505bc478d877a544ffb27f559

url: https://app.cloopen.com:8883

posted @ 2025-07-10 10:38  星河霓虹  阅读(35)  评论(0)    收藏  举报