django1


Introduction

课程特点

  1. 学习难度大,大部分内容需要理解并记忆。

  2. 文件较多,易混淆。

  3. 学习阶段注重框架使用,工作阶段注重实现业务逻辑。

  4. 综合应用强,小练习少。


学习建议:

  1. 课前进行预习,课后进行复习,善于查看报错信息,增强自我排错能力。

  2. 课余时间自行搭建开发环境,为后续工作做准备。


课程划分:

  1. Django01Django基础应用部分;

  2. Django02Django高级应用部分;

  3. DaDaBlogDjango综合项目。

Django介绍

  • 起源与应用

  • 虚拟环境(自行扩展)

  • 安装


起源&应用

  • 2005年发布,采用Python语言编写的开源web框架

  • 早期的时候Django主做新闻和内容管理的

  • 一个重量级的 Python Web框架,Django 配备了常用的大部分组件

    1. 基本配置

    2. 路由系统

    3. 原生HTML模板系统

    4. 视图 view

    5. Model模型,数据库连接和ORM数据库管理

    6. 中间件

    7. Cookie & Seesion

    8. 分页

    9. 数据库后台管理系统admin

  • Django的用途

    • 网站后端开发

    • 微信公众号、微信小程序等后台开发

       

    • ![image-20210911144309152](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144309152.png)

    • 基于HTTP/HTTPS协议的后台服务器开发

      • 在线语音/图像识别服务器

      • 在线第三方身份验证服务器等

      • ![image-20210911144332987](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144332987.png)

      • 创建虚拟环境

        在开发过程中, 当需要使用python的某些工具包/框架时需要联网安装

        比如联网安装Django框架sudo pip install Django

        提示:使用如上命令, 会将Django安装到/usr/local/lib/python3.6/dist-packages路径下

        问题:如果在一台电脑上,,想开发多个不同的项目,,需要用到同一个包的不同版本,,如果使用上面的命令,在同一个目录下安装或者更新,,新版本会覆盖以前的版本, 其它的项目就无法运行了。

        解决方案 : 虚拟环境

        作用 : 虚拟环境可以搭建独立的python运行环境, 使得单个项目的运行环境与其它项目互不影响。 所有的虚拟环境都位于/home/下的隐藏目录.virtualenvs

        这里给大家举一个简单的例子,桌面上有一个word文件,我们打开修改这个文件,修改了一会之后发现还是原来的文件比较好,这个时候我想找回原来的文件就比较困难了。那么怎么办呢?就有这样一种解决方案,在修改文件之前,先复制一份,然后在副本文件里进行修改,这样即使发现修改有错,也不会影响原始文件。

        虚拟环境其实就是对真实pyhton环境的复制,这样我们在复制的python环境中安装包就不会影响到真实的python环境。通过建立多个虚拟环境,在不同的虚拟环境中开发项目就实现了项目之间的隔离。

        创建

        首先安装虚拟环境,命令如下:

         
         
         
         
         
         
         
        sudo pip3 install virtualenv #安装虚拟环境
        Copy
         

        接下来还要安装虚拟环境扩展包,命令如下:

         
         
         
         
         
         
         
        sudo pip3 install virtualenvwrapper
        Copy
         

        检车安装虚拟环境相关的扩展包:

        ![image-20210911144350196](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144350196.png)

        安装虚拟环境包装器的目的是使用更加简单的命令来管理虚拟环境。

         
         
         
         
         
         
         
        安装完虚拟环境后,如果提示找不到mkvirtualenv命令,须配置环境变量:
        # 1、创建目录用来存放虚拟环境 mkdir  $HOME/.virtualenvs 
        # 2、修改用户家目录下的配置文件.bashrc,添加如下内容: 
        sudo vim ~/.bashrc
        # 虚拟环境
        export VIRTUALENVWRAPPER=/usr/bin/python3
        export WORKON_HOME=$HOME/.virtualenvs 
        export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
        source /usr/local/bin/virtualenvwrapper.sh
        # source ~/.local/bin/virtualenvwrapper.sh
        # 3、运行 source ~/.bashrc
        Copy
        如果提示 "bash: /home/tarena/.local/bin/virtualenvwrapper.sh: 没有那个文件或目录"
        则使用 which virtualenvwrapper.sh 查看所在路径,并且将source后面的路径 换成显示后的路径
        Copy
         

        使用source .bashrc命令使配置文件生效。

        创建python3虚拟环境的命令如下:

         
         
         
         
         
         
         
        mkvirtualenv 虚拟环境名称
        例:
        mkvirtualenv py3_Django
        Copy
         

        ![image-20210911144434045](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144434045.png)

        小总结

        • 创建成功后,会自动工作在这个虚拟环境上。

        • 创建虚拟环境需要联网。

        • 工作在虚拟环境上,提示符最前面会出现"(虚拟环境名称)"。

        • 所有的虚拟环境,都位于/home/tarena/下的隐藏目录.virtualenvs下。

        退出

        退出的虚拟环境命令如下:

         
         
         
         
         
         
         
        deactivate
         

        ![image-20210911144442199](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144442199.png)

        退出虚拟环境

        查看与使用

        查看所有虚拟环境的命令如下:

        提示:workon后面有个空格,再按两次tab键。

         
         
         
         
         
         
         
        workon 两次tab健
         

        查看虚拟环境

        使用虚拟环境的命令如下:

        写出名称的前部分后,可以使用tab键补齐

         
         
         
         
         
         
         
        workon 虚拟环境名称
        例:workon py3_Django
         

        ![image-20210911144449127](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144449127.png)

        使用py3_Django虚拟环境

        提示:注意提示符的变化

        虚拟环境安装包

         
         
         
         
         
         
         
        pip3 install Django==2.2.12
         

        ![image-20210911144454600](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144454600.png)

        ![image-20210911144459934](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144459934.png)

        在虚拟环境中,如果想要使用一些包的话,正常安装即可。

        删除

        删除虚拟环境的命令如下:

        rmvirtualenv 虚拟环境名称
        例:先退出:deactivate
        再删除:rmvirtualenv py3_Django

        ![image-20210911144505563](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144505563.png)

        友情提示:

        以上是在ubuntu18.04系统中进行操作,其他系统的后续更新。

        Django的安装


        版本

        https://www.djangoproject.com/download/#supported-versions

        ![image-20210911144513032](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144513032.png)

        ![image-20210911144518689](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144518689.png)


        安装与卸载

        • 查看已安装的版本

            >>> import django
            >>> print(django.VERSION)
            (2, 2, 12, 'final', 0)

        • 安装:

          1. 在线安装:

            sudo pip3 install django  # 安装django的最新版本
            或
            sudo pip3 install django[==版本]  # 安装django的指定版本
            
            # 如:
            sudo pip3 install django==2.2.12 # 安装 Django 2.2.12 版本
            
            sudo pip3 install django==2.2.12 -i https://pypi.mirrors.ustc.edu.cn/simple/
          2. 离线安装:

            1. 下载安装包:官网下载离线安装包,复制进虚拟机
            
            2. 安装离线包
            # 解压缩
            tar -xvf Django-2.2.12.tar.gz
            # 进入目录
            cd Django-2.2.12
            # 执行安装
            sudo python3 setup.py install
          3. 检查是否成功:

            sudo pip3 freeze | grep -i "Django"
            Django==2.2.12
            Copy

            ![image-20210911144529123](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144529123.png)

        • 卸载:

            pip3 uninstall django

        Django的开发环境:

        • Django 2.2.12 支持 3.5,3.6,3.7,3.8

         

         

        创建项目工程


        创建工程的命令为:

        django-admin startproject 工程名称

        例如:想要在桌面的code目录中创建一个名为demo的项目工程,可执行如下命令:

        cd ~/Desktop/code
        django-admin startproject demo

        执行后,会多出一个新目录名为demo,此即为新创建的工程目录

         

        Django项目的目录结构

        Django项目的目录结构

        • 示例:

          $ django-admin startproject mysite1
          $ tree mysite1/
          mysite1/
          ├── manage.py
          └── mysite1
              ├── __init__.py
              ├── settings.py
              ├── urls.py
              └── wsgi.py
          
          1 directory, 5 files
        • 项目目录结构解析:

          • manage.py

            • 此文件是项目管理的主程序,在开发阶段用于管理整个项目的开发运行的调式

            • manage.py

               

              包含项目管理的子命令, 如:

              • python3 manage.py runserver 启动服务

              • python3 manage.py startapp 创建应用

              • python3 manage.py migrate 数据库迁移

              • ...

          • mysite1 项目文件夹

            • 项目包的主文件夹(默认与项目名称一致)

            • __init__.py

              • 包初始化文件,当此项目包被导入(import)时此文件会自动运行

            • wsgi.py
              • WSGI 即 Web Server Gateway Interface

              • WEB服务网关接口的配置文件,仅部署项目时使用

            • urls.py
              • 项目的主路由配置文件,所有的动态路径必须先走该文件进行匹配

            • settings.py
              • Django项目的配置文件, 此配置文件中的一些全局变量将为Django框架的运行传递一些参数

              • setting.py 配置文件,启动服务时自动调用,

              • 此配置文件中也可以定义一些自定义的变量用于作用全局作用域的数据传递


        settings.py 文件介绍

        https://docs.djangoproject.com/en/2.2/ref/settings/

        公有配置

        1. BASE_DIR

          • 用于绑定当前项目的绝对路径(动态计算出来的), 所有文件都可以依懒此路径

        2. DEBUG

          • 用于配置Django项目的启动模式, 取值:

            1. True 表示开发环境中使用 调试模式(用于开发中)

            2. False 表示当前项目运行在生产环境中(不启用调试)

        3. ALLOWED_HOSTS

          • 设置允许访问到本项目的host请求头的值,取值:

            1. [] 空列表,表示只有host请求头为127.0.0.1, localhost能访问本项目 - DEBUG = True时生效

            2. ['*'],表示任何请求头的host都能访问到当前项目

            3. ['192.168.1.3', '127.0.0.1'] 表示只有当前两个host头的值能访问当前项目

            4. 注意:

              • 如果要在局域网其它主机也能访问此主机,启动方式应使用如下模式:

          • python3 manage.py runserver 0.0.0.0:5000 # 指定网络设备如果内网环境下其他主机想正常访问该站点,需加`ALLOWED_HOSTS = ['内网ip']

        4. INSTALLED_APPS

          • 指定当前项目中安装的应用列表

        5. MIDDLEWARE

          • 用于注册中间件

        6. TEMPLATES

          • 用于指定模板的配置信息

        7. DATABASES

          • 用于指定数据库的配置信息

        8. LANGUAGE_CODE

          • 用于指定语言配置

          • 取值:

            • 英文 : "en-us"

            • 中文 : "zh-Hans"

        9. TIME_ZONE

          • 用于指定当前服务器端时区

          • 取值:

            • 世界标准时间: "UTC"

            • 中国时区 : "Asia/Shanghai"

        10. ROOT_URLCONF

          • 用于配置根级 url 配置 'mysite1.urls'

          • 如:

            • ROOT_URLCONF = 'mysite1.urls'

        私有配置

        settings.py 中也可以添加 开发人员 自定义的配置

        配置建议:名字尽量个性化 - 以防覆盖掉公有配置;例如: ALIPAY_KEY = 'xxxxxx'

        注:

        settings.py中的所有配置项,都可以按需的在代码中引入

        此模块可以通过 from django.conf import settings 导入和使用

         

        Django项目启动与终止

        运行开发服务器

        在开发阶段,为了能够快速预览到开发的效果,django提供了一个纯python编写的轻量级web服务器,仅在开发阶段使用。

        运行服务器命令如下:

        python3 manage.py runserver ip:端口
        或:
        python3 manage.py runserver

        可以不写IP和端口,默认IP是127.0.0.1,默认端口为8000

        如果想要更换端口,则可以使用 python3 manage.py runserver 端口号

        启动后可见如下信息:

        ![image-20210911144602005](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144602005.png)

        在浏览器中输入网址127.0.0.1:8000便可看到效果。

        ![image-20210911144607947](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144607947.png)

        • django默认工作在调式Debug 模式下,如果增加、修改、删除文件,服务器会自动重启。

        • ctrl+c 停止服务器。


        关闭服务

        方法一:

        runserver 启动终端下:

        • 执行 ctrl + c 可以关闭 Django 服务。

        方法二:

        在其他终端下

        • 执行 sudo lsof -i:8000 查看出 Django 的 进程id

        • 执行 kill -9 对应 Django 进程 id


        启动常见问题

        问题: Error: That port is already in use

        问题原因:端口已被使用,证明当前 Django 启动时,默认监听的 8000 端口已被其他进程占用

        解决方案:参照关闭服务方法二

         

        URL和视图函数

        URL 介绍

        URL即 **统一资源定位符**Uniform Resource Locator

        • 作用:

          • 用来表示互联网上某个资源的地址。

        • 说明:

          • 互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它

        URL的一般语法格式为:

        protocol :// hostname[:port] / path [?query][#fragment]

        如:

        http://tts.tmooc.cn/video/showVideo?menuId=657421&version=AID201908#subject

        说明:

        • protocol(协议)http:

          • http 通过 HTTP 访问该资源。 格式 HTTP://

          • https 通过安全的 HTTPS 访问该资源。 格式 HTTPS://

          • file 资源是本地计算机上的文件。格式: file:///

        • hostname(主机名)tts.tmooc.cn

          • 是指存放资源的服务器的域名系统(DNS) 主机名、域名 或 IP 地址。

        • port(端口号)80

          • 整数,可选,省略时使用方案的默认端口;

          • 各种传输协议都有默认的端口号,如http的默认端口为80

        • path(路由地址)video/showVideo

          • 由零或多个"/"符号隔开的字符串,一般用来表示主机上的一个目录或文件地址。路由地址决定了服务器端如何处理这个请求

        • query (查询) ?menuId=757421&version=AID999

          • 可选,用于给动态网页传递参数,可有多个参数,用"&"符号隔开,每个参数的名和值用"="符号隔开。

        • fragment(信息片断)#subject

          • 字符串,用于指定网络资源中的片断。例如一个网页中有多个名词解释,可使用fragment直接定位到某一名词解释。

            注: []代表其中的内容可省略

            测试markdown样式

         

         

        Django中如何处理URL的请求

        ![image-20210911144632017](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144632017.png)

        浏览器 http://127.0.0.1:8000/page/2005/

        1. Django 从配置文件中 根据 ROOT_URLCONF 找到 主路由文件;默认情况下,该文件在 项目同名目录下的urls; 例如 mysite1/mysite1/urls.py

        2. Django 加载 主路由文件中的 urlpatterns 变量

        3. 依次匹配 urlpatterns 中的 URL, 匹配到第一个合适的中断后续匹配

        4. 匹配成功 - 调用对应的视图函数处理请求,返回响应

        5. 匹配失败 - 返回404响应

        # 主路由-urls.py样例
        from django.urls import path
        from . import views
        
        urlpatterns = [
            path('admin/', admin.site.urls)
            path('page/2003/', views.page_2003),
            path('page/2004/', views.page_2004),
        ]

         

        视图函数

        ##

        视函数使用

        视图函数是用于接收一个浏览器请求并通过HttpResponse 对象返回数据的函数。此函数可以接收浏览器请求并根据业务逻辑返回相应的内容给浏览器。

        视图处理的函数的语法格式:

        def xxx_view(request[, 其它参数...]):
            return HttpResponse对象
        Copy

        参数:

        • request用于绑定HttpRequest对象,通过此对象可以获取浏览器的参数和数据

        返回值

        HttpResponse的对象;

        Django会提供一系列的 response 对象;

        试图函数示例:

        视图处理函数 views.py

        # file : <项目同名文件夹下>/views.py
        from django.http import HttpResponse
        
        def page1_view(request):
            html = "<h1>这是第1个页面</h1>"
            return HttpResponse(html)

         

        Django 中的路由配置

         

        settings.py中的ROOT_URLCONF 指定了主路由配置列表urlpatterns的文件位置

        urls.py 主路由配置文件

        # file : <项目同名文件夹>/urls.py
        urlpatterns = [
            path('admin/', admin.site.urls),
            ...  # 此处配置主路由
        ]
        Copy

        path() 函数

        用于描述路由与视图函数的对应关系

        • 模块

          • from django.urls import path

        • 语法:

            path(route, views, name=None)
          
            参数:
                1. route: 字符串类型,匹配的请求路径
                2. views: 指定路径所对应的视图处理函数的名称
                3. name: 为地址起别名,在模板中地址反向解析时使用
          Copy

        练习

        path转换器

        语法:<转换器类型:自定义名>

        作用:若转换器类型匹配到对应类型的数据,则将数据按照关键字传参的方式传递给视图函数

        示例:path('page/<int:age>', views.xxx)

        转换器效果案例
        str 匹配除了 '/' 之外的非空字符串 "v1/users/\<str:username>" 匹配 /v1/users/xiaohanghang
        int 匹配0或任何正整数。返回一个 int "page/\<int:page>" 匹配 /page/100
        slug 匹配任意由 ASCII 字母或数字以及连字符和下划线组成的短标签 "detail/\<slug:sl>"匹配 /detail/this-is-django
        path 匹配非空字段,包括路径分隔符 '/' "v1/users/\<path:ph>"匹配/v1/goods/a/b/c

        练习:小计算器

        • 定义一个路由的格式为:

        • 从路由中提取数据,做相应的操作后返回给浏览器

        • 如:

            输入: 127.0.0.1:8000/100/add/200
                页面显示结果:300
          
            输入: 127.0.0.1:8000/100/sub/200
                页面显示结果:-100
          
            输入: 127.0.0.1:8000/100/mul/200
                页面显示结果:20000
          Copy

        re_path()函数

        • url 的匹配过程中可以使用正则表达式进行精确匹配

        • 语法:

          • re_path(reg, view, name=xxx)

          • 正则表达式为命名分组模式(?P<name>pattern) ;匹配提取参数后用关键字传参方式传递给视图函数

        示例:

        • 路由配置文件

            # file : <项目同名文件夹>/urls.py
            # 以下示例匹配
            # 可匹配 http://127.0.0.1:8000/20/mul/40
            # 不可匹配 http://127.0.0.1:8000/200/mul/400
          
            urlpatterns = [
                path('admin/', admin.site.urls),
                re_path(r'^(?P<x>\d{1,2})/(?P<op>\w+)/(?P<y>\d{1,2})$',views.cal_view),
            ]
          Copy

        练习:

        • 访问地址:

        • 最终输出: 生日为: xxxx年xx月xx日

        • 如:

            输入网址: http://127.0.0.1:8000/birthday/2015/12/11
            显示为: 生日为:2015年12月11日
          
            输入网址: http://127.0.0.1:8000/birthday/2/28/2008
            显示为: 生日为:2008年2月28日
          Copy

         

        请求和响应

        HTTP协议的请求和响应

        • 请求是指浏览器端通过HTTP协议发送给服务器端的数据

        • 响应是指服务器端接收到请求后做相应的处理后再回复给浏览器端的数据

        ![image-20210911144706510](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144706510.png)

        请求

        请求样式

        ![image-20210911144719893](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144719893.png)

        请求中的方法

        • 根据HTTP标准,HTTP请求可以使用多种请求方法。

        • HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法(最常用)

        • HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACECONNECT 方法。

        • HTTP1.1 请求详述

        序号方法描述
        1 GET 请求指定的页面信息,并返回实体主体。
        2 HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
        3 POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
        4 PUT 从客户端向服务器传送的数据取代指定的文档的内容。
        5 DELETE 请求服务器删除指定的页面。
        6 CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
        7 OPTIONS 允许客户端查看服务器的性能。
        8 TRACE 回显服务器收到的请求,主要用于测试或诊断。

        Django 中的请求

        请求在Django中实则就是 视图函数的第一个参数,即HttpRequest对象

        Django接收到http协议的请求后,会根据请求数据报文创建HttpRequest对象

        HttpRequest对象 通过属性 描述了 请求的 所有相关信息

        HttpRequest 对象

        • path_info: URL字符串

        • method:字符串,表示HTTP请求方法,常用值:'GET'、'POST'

        • GET:QueryDict查询字典的对象,包含get请求方式的所有数据,查询字符串的所有数据

        • POST:QueryDict查询字典的对象,包含post表单提交方式的所有数据

        • FILES:类似于字典的对象,包含所有的上传文件信息

        • COOKIES:Python字典,包含所有的cookie,键和值都为字符串

        • session:似于字典的对象,表示当前的会话

        • body: 字符串,请求体的内容(POST或PUT)

        • scheme : 请求协议('http'/'https')

        • request.get_full_path() : 请求的完整路径

        • request.get_host(): 请求的主机

        • request.META
          Copy

          : 请求中的元数据(消息头)

          • request.META['REMOTE_ADDR'] : 客户端IP地址

        响应

        当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码的信息头用以响应浏览器的请求。

        响应样式

        ![image-20210911144733918](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144733918.png)

        响应状态码

        • HTTP状态码的英文为HTTP Status Code

        • 下面是常见的HTTP状态码:

          • 200 - 请求成功

          • 301 - 永久重定向-资源(网页等)被永久转移到其它URL

          • 302 - 临时重定向

          • 404 - 请求的资源(网页等)不存在

          • 500 - 内部服务器错误

        • HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。HTTP状态码共分为5种类型

        分类分类描述
        1** 信息,服务器收到请求,需要请求者继续执行操作
        2** 成功,操作被成功接收并处理
        3** 重定向,需要进一步的操作以完成请求
        4** 客户端错误,请求包含语法错误或无法完成请求
        5** 服务器错误,服务器在处理请求的过程中发生了错误

        Django 中的响应对象

        HttpResponse 对象

        构造函数格式:

        • HttpResponse(content=响应体, content_type=响应体数据类型, status=状态码)

        作用:

        • 向客户端浏览器返回响应,同时携带响应体内容

        参数:

        • content:表示返回的内容。

        • status_code:返回的HTTP响应状态码(默认为200)。

        • content_type:指定返回数据的的MIME类型(默认为"text/html")。浏览器会根据这个属性,来显示数据。如果是text/html,那么就会解析这个字符串,如果text/plain,那么就会显示一个纯文本。

          • 常用的Content-Type如下:

            • 'text/html'(默认的,html文件)

            • 'text/plain'(纯文本)

            • 'text/css'(css文件)

            • 'text/javascript'(js文件)

            • 'multipart/form-data'(文件提交)

            • 'application/json'(json传输)

          • 'application/xml'(xml文件)

            注: 关键字MIME(Multipurpose Internet Mail Extensions)是指多用途互联网邮件扩展类型。

        HttpResponse 子类

        类型作用状态码
        HttpResponseRedirect 重定向 302
        HttpResponseNotModified 未修改 304
        HttpResponseBadRequest 错误请求 400
        HttpResponseNotFound 没有对应的资源 404
        HttpResponseForbidden 请求被禁止 403
        HttpResponseServerError 服务器错误 500

         

Django中处理GET请求

Django处理GET和POST请求

  • 无论是GET还是POST,统一都由视图函数接收请求,通过判断request.method区分具体的请求动作

  • 样例:

    if request.method == 'GET':
        处理GET请求时的业务逻辑
    elif request.method == 'POST':
        处理POST请求的业务逻辑
    else:
        其他请求业务逻辑
    Copy

Django 中GET 处理

GET 请求

  • GET请求动作,一般用于向服务器获取数据

  • 能够产生GET请求的场景:

    • 浏览器地址栏中输入URL,回车后

    • <a href="地址?参数=值&参数=值">

    • form表单中的methodget

      <form method='get' action="/user/login">
          姓名:<input type="text" name="uname">
      </form>
      Copy
  • GET请求方式中,如果有数据需要传递给服务器,通常会用查询字符串(Query String)传递 【注意:不要传递敏感数据】

    • URL 格式: xxx?参数名1=值1&参数名2=值2...

      • 如: http://127.0.0.1:8000/page1?a=100&b=200

    • 服务器端接收参数

      获取客户端请求GET请求提交的数据

方法示例

request.GET['参数名']  # QueryDict
request.GET.get('参数名','默认值')
request.GET.getlist('参数名')

# mypage?a=100&b=200&c=300&b=400
# request.GET=QueryDict({'a':['100'], 'b':['200','400'], 'c':['300']})
# a = request.GET['a']
# b = request.GET['b']  # Error
Copy

思考:之前的计算器功能,能否拿查询字符串做?

Django中处理POST请求

Django中处理POST请求

POST 请求

  • POST请求动作,一般用于向服务器提交大量数据/隐私数据

  • 客户端通过表单等POST请求将数据传递给服务器端,如:

    <form method='post' action="/login">
        姓名:<input type="text" name="username">
        <input type='submit' value='登陆'>
    </form>
    Copy

服务器端接收参数

通过request.method来判断是否为POST 请求,如:

if request.method == 'POST':
    处理POST请求的数据并响应
else:
    处理非POST 请求的响应

使用post方式接收客户端数据

request.POST['参数名']  # request.POST 绑定QueryDict
request.POST.get('参数名','')
request.POST.getlist('参数名')

取消 csrf 验证

  • 取消csrf验证,否则Django将会拒绝客户端发来的POST请求,报 403 响应

  • 禁止掉 settings.pyMIDDLEWARE 中的 CsrfViewsMiddleWare的中间件

    MIDDLEWARE = [
        ...
        # 'django.middleware.csrf.CsrfViewMiddleware',
        ...
    ]

 

Django框架设计模式

Django框架设计模式

传统的MVC

MVC代表Model-View-Controller(模型-视图-控制器)模式。

  • M模型层(Model), 主要用于对数据库层的封装

  • V视图层(View),用于向用户展示结果(WHAT + HOW)

  • C 控制(Controller ,用于处理请求、获取数据、返回结果(重要)

作用:降低模块间的耦合度(解耦)

![image-20210911144748916](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144748916.png)

Django中的MTV模式

MTV代表模型-模板-视图(模型-模板-视图)模式。

  • M 模型层(Model) 负责与数据库交互

  • T模板层(Template) 形象地展示内容到浏览器 (HOW)

  • V视图层(View)是核心,负责接收请求、获取数据、返回结果(WHAT)

作用:降低模块间的耦合度(解耦)

![image-20210911144758338](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144758338.png)

 

MTV-诞生记

![image-20210911144828640](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911144828640.png)\

模板

模板

什么是模板?

  1. 模板是可以根据字典数据动态变化的html网页

  2. 模板可以根据视图中传递的字典数据动态生成相应的 html 网页。

![image-20210911161512294](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911161512294.png)

模板的配置

创建模板文件夹 <项目名>/templates

settings.pyTEMPLATES配置项

  • BACKEND : 指定模板的引擎

  • DIRS : 模板的搜索目录(可以是一个或多个)

  • APP_DIRS : 是否要在应用中的 templates 文件夹中搜索模板文件

  • OPTIONS : 有关模板的选项

  • 配置项中 需要修改部分

    设置DIRS - 'DIRS': [os.path.join(BASE_DIR, 'templates')],

# file: settings.py
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        # 'DIRS': [],
        'DIRS': [os.path.join(BASE_DIR, 'templates')],  # 添加模板路径
        'APP_DIRS': True,  # 是否索引各app里的templates目录
        ...
    },
]

 

模板的加载

模板的加载方式

方案一

通过 loader 获取模板,通过HttpResponse进行响应

在视图函数中

from django.template inport loader

# 1. 通过 loader 加载模板
t = loader.get_template("模板文件名")

# 2. 将 t 转换成 HTML 字符串
html = t.render(字典数据)

# 3. 用响应对象将转换的字符串内容返回给浏览器
return HttpResponse(html)
Copy

方案二

使用 render() 直接加载并响应模板

在视图函数中:

from django.shortcuts import render

return render(request, '模板文件名', 字典数据)
Copy

试图层与模板层之间的交互

  1. 视图函数中可以将Python变量封装到字典中传递到模板 样例:

    def xxx_view(request):
        dic = {
                "变量1":"值1",
                "变量2":"值2",
            }
        return render(request, "xxx.html", dic)
    Copy
  2. 模板中, 我们可以用{}的语法 调用视图传进来的变量

 

模板的变量

模板的变量

模板的变量

视图函数中可以将Python变量封装到 字典 中传递到模板上

样例:

def xxx_view(request):
    dic = {
            "变量1":"值1",
            "变量2":"值2",
        }
    return render(request, "xxx.html", dic)
Copy

模板中使用变量的方法

{{ 变量名 }}
{{ 变量名.index }}
{{ 变量名.key}}
{{ 对象.方法 }}
{{ 函数名 }}
Copy

能够传递到模板中的数据类型:

  • str - 字符串 int - 整型

  • list - 数组 tuple - 元组

  • dict - 字典 func - 方法

  • obj - 类实例化的对象

 

模板的标签

模板的标签

作用:将一些服务器端的功能嵌入到模板中,例如流程控制等

标签语法

{% 标签 %}
...
{% 结束标签 %}
Copy

模板标签 - if标签

{% if 条件表达式1 %}
...
{% elif 条件表达式2 %}
...
{% elif 条件表达式3 %}
...
{% else %}
...
{% endif %}
Copy

注意

  1. if 条件表达式里可以用的运算符 ==, !=, <, >, <=, >=, in, not in, is, is not, not、and、or

  2. if标记中使用实际括号是无效的语法。 如果您需要它们指示优先级,则应使用嵌套的if标记。

    官方文档:https://docs.djangoproject.com/zh-hans/2.2/ref/templates/builtins/#if

模板标签 - if标签 - 练习

写一个简单的计算器页面,能够在服务端进行简单加减乘除计算

 

 

= 3

<form action='/mycal' method='post'>
    <input type='text' name="x" value="1">
    <select name='op'>
        <option value="add"> +加 </option>
        <option value="sub"> -减 </option>
        <option value="mul"> *乘 </option>
        <option value="div"> /除 </option>
    </select>
    <input type='text' name="y" value="2"> = <span>3</span>
    <div>
        <input type="submit" value='开始计算'>
    </div>
</form>
Copy

模板标签 - for标签

语法:

{% for 变量 in 可迭代对象 %}
    ... 循环语句
{% empty %}
    ... 可迭代对象无数据时填充的语句
{% endfor %}
Copy

官方文档:https://docs.djangoproject.com/en/2.2/ref/templates/builtins/#for

内置变量 - forloop

变量描述
forloop.counter 循环的当前迭代(从1开始索引)
forloop.counter0 循环的当前迭代(从0开始索引)
forloop.revcounter counter值得倒序
forloop.revcounter0 revcounter值的倒序
forloop.first 如果这是第一次通过循环,则为真
forloop.last 如果这是最后一次循环,则为真
forloop.parentloop 当嵌套循环,parentloop 表示外层循环

 

模板的过滤器

模板的过滤器

模板层 — 过滤器

定义:在变量输出时对变量的值进行处理

作用:可以通过使用 过滤器来改变变量的输出显示

语法:{{ 变量 | 过滤器1:'参数值1' | 过滤器2:'参数值2' ... }}

常用过滤器

过滤器说明
lower 将字符串转换为全部小写。
upper 将字符串转换为大写形式
safe 默认不对变量内的字符串进行html转义
add: "n" 将value的值增加 n
truncatechars:'n' 如果字符串字符多于指定的字符数量,那么会被截断。 截断的字符串将以可翻译的省略号序列(“...”)结尾。

官方文档:https://docs.djangoproject.com/en/2.2/ref/templates/builtins/

 

模板的继承

模板的继承

请看如下样式:

![image-20210911161525591](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911161525591.png)

模板继承可以使父模板的内容重用,子模板直接继承父模板的全部内容并可以覆盖父模板中相应的块

语法 - 父模板中:

  • 定义父模板中的块 block 标签

  • 标识出哪些在子模块中是允许被修改的

  • block标签:在父模板中定义,可以在子模板中覆盖

语法 - 子模板中

继承模板 extends 标签(写在模板文件的第一行)

  • 例如:

    ![img](http://xa-yanh.com/django/img/%E6%A8%A1%E6%9D%BF%E7%BB%A7%E6%89%BF1.png)

子模板 重写父模板中的内容块

{% block block_name %}
定义模板块,此模板块可以被子模板重新定义的同名块覆盖
{% endblock block_name %}
Copy

重写的覆盖规则

不重写,将按照父模板的效果显示

重写,则按照重写效果显示

注意

模板继承时,服务器端的动态内容无法继承

参考文档:https://docs.djangoproject.com/en/2.2/ref/templates/language/#for-template-blocks

 

URL反向解析

URL反向解析

再谈 url

代码中 url 出现位置

  1. 模板【html中】

    1. <a href='url'>超链接</a>
            点击后 页面跳转至 url
    2. <form action='url'  method='post'> 
            form表单中的数据 用post方法提交至 url
    Copy
  2. 视图函数中 - 302跳转 HttpResponseRedirect('url')

    • 将用户地址栏中的地址跳转到 url

代码中 url 书写规范

  1. 绝对地址 http://127.0.0.1:8000/page/1

  2. 相对地址

    • '/page/1' - ‘/’开头的相对地址,浏览器会把当前地址栏里的 协议,ip和端口加上这个地址,作为最终访问地址, 即如果当前页面地址栏为 http://127.0.0.1:8000/page/3; 当前相对地址最终结果为 http://127.0.0.1:8000 + /page/1

    • 'page/1' - 没有‘/’开头的相对地址,浏览器会根据当前url的最后一个/之前的内容 加上 该相对地址 作为最终访问地址,例如当前地址栏地址为 http://127.0.0.1:8000/topic/detail; 则该相对地址最终结果为 http://127.0.0.1:8000/topic/ + page/1

url 反向解析

url 反向解析是指在视图或模板中,用path定义的名称来动态查找或计算出相应的路由

path 函数的语法

path(route, views, name="别名")
path('page', views.page_view, name="page_url")
Copy

根据path中的name=关键字传参给 url确定了个唯一确定的名字,在模板或视图中,可以通过这个名字反向推断出此url信息

模板中

  • 通过 url 标签 实现地址的反向解析

    ![img](http://xa-yanh.com/django/img/%E5%8F%8D%E5%90%91%E8%A7%A3%E6%9E%901.png)

  • 在视图函数中 ->可调用 django中的 reverse 方法进行反向解析

    from django.urls import reverse
    reverse('别名', args=[], kwargs={})
    
    eg:
    print(reverse('pagen',args=[300]))
    print(reverse('person',kwargs={'name':'xixi','age':18}))
    Copy

 

静态文件

静态文件

什么是静态文件

  • 如:图片,css,js,音频,视频

![img](http://xa-yanh.com/django/img/%E9%9D%99%E6%80%81%E6%96%87%E4%BB%B6.png)

 

静态文件配置

静态文件配置

  • settings.py 中配置一下两项内容:

  • 配置静态文件的访问路径

    • 通过哪个url地址找静态文件

    • STATIC_URL = '/static/'

    • 说明:

      • 指定访问静态文件时是需要通过/static/xxx127.0.0.1:8000/static/xxx

      • xxx 表示具体的静态资源位置

  • 配置静态文件的存储路径 STATICFILES_DIRS

    • STATICFILES_DIRS保存的是静态文件在服务器端的存储位置

  • 示例:

    # file: setting.py
    STATICFILES_DIRS = (
        os.path.join(BASE_DIR, "static"),
    )
    Copy

 

静态文件使用

静态文件访问

使用静态文件的访问路径进行访问

  • 访问路径: STATIC_URL = '/static/'

  • 示例:

    <img src="/static/images/lena.jpg">
    Copy
    <img src="http://127.0.0.1:8000/static/images/lena.jpg">
    Copy

通过 static 标签访问静态文件

![img](http://xa-yanh.com/django/img/%E9%9D%99%E6%80%81%E6%96%87%E4%BB%B62.png)

 

 

Django中的应用

Django中的应用

应用在Django项目中是一个独立的业务模块,可以包含自己的路由,视图,模板,模型

![image-20210911161546029](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911161546029.png)

 

创建应用app

创建应用app

步骤1

manage.py 中的子命令 startapp 创建应用文件夹

python3 manage.py startapp music
Copy

步骤2

settings.pyINSTALLED_APPS 列表中配置安装此应用

INSTALLED_APPS = [
  # ....
  'user',  #用户信息模块
  'music',  #音乐模块
]
Copy

 

应用目录结构

应用目录结构

  1. migrations   文件夹
    • 保存数据迁移的中间文件

  2. __init__.py
    • 应用子包的初始化文件

  3. admin.py
    • 应用的后台管理配置文件

  4. apps.py
    • 应用的属性配置文件

  5. models.py
    • 与数据库相关的模型映射类文件

  6. tests.py
    • 应用的单元测试文件

  7. views.py
    • 定义视图处理函数的文件

    应用的分布式路由

    应用的分布式路由

    Django中,主路由配置文件(urls.py)可以不处理用户具体路由,主路由配置文件的可以做请求的分发(分布式请求处理)。具体的请求可以由各自的应用来进行处理

    ![image-20210911161554395](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911161554395.png)

     

配置分布式路由

配置分布式路由

步骤一 : 主路由中调用 include 函数

语法:include('app名字.url模块名')

作用:用于将当前路由转到各个应用的路由配置文件的 urlpatterns 进行分布式处理

http://127.0.0.1:8000/music/index 为例:

from django.urls import path, include
from . import views

urlpatterns = [
    path('admin/', admin.site.urls),    
    path('test_static/', views.test_static),
    path('music/', include('music.urls')),
]
Copy

步骤2 : 应用下配置urls.py

应用下手动创建urls.py文件

内容结构同主路由完全一样

from django.urls import path, include
from . import views

urlpatterns = [
    # http:127.0.0.0:8000/music/index
    path('index', views.index_view),
]
Copy

练习:配置分布式路由

1.创建两个应用    
    1.创建 sport 应用,并注册
    2.创建 news  应用,并注册

2.创建分布式路由系统
    1. http://127.0.0.1:8000/sport/index
        交给 sport 应用中的 index_view() 函数处理
    2. http://127.0.0.1:8000/news/index
        交给 news  应用中的 index_view() 函数处理
Copy

应用下的模板

应用下的模板

应用内部可以配置模板目录

  1. 应用下手动创建 templates 文件夹

  2. settings.py中 开启 应用模板功能 TEMPLATES 配置项中 的 'APP_DIRS' 值 为 True 即可

应用下templates 和 外层templates 都存在时,django得查找模板规则

  1. 优先查找外层templates目录下的模板

  2. INSTALLED_APPS配置下的 应用顺序 逐层查找

模型层及ORM介绍

模型层及ORM介绍

 

Django中配置使用mysql数据库

Django 中配置使用 mysql 数据库

安装

  1. 安装 mysqlclient [版本 mysqlclient 1.3.13以上 ,官网目前为1.4.x]

  2. 安装前确认ubuntu是否已安装

     

    python3-dev

    default-libmysqlclient-dev
    1. sudo apt list --installed|grep -E 'libmysqlclient-dev|python3-dev'

    2. 若命令无输出则需要安装 - sudo apt-get install python3-dev default-libmysqlclient-dev

  3. sudo pip3 install mysqlclient

创建数据库

1. 进入mysql数据库 执行

  1. create database 数据库名 default charset utf8

  2. 通常数据库名跟项目名保持一致

    create database mysite1 default charset utf8 collate utf8_general_ci;
    Copy

2. settings.py 里进行数据库的配置

  1. 修改 DATABASES 配置项的内容, 由sqlite3 变为 mysql

  2. DATABASE 配置样例

    • sqlite 数据库配置

    # file: settings.py
    DATABASES = {
        'default': {
                'ENGINE': 'django.db.backends.sqlite3',
                'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        }
    }
    Copy
    • mysql 数据库配置

    DATABASES = {
        'default' : {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'mywebdb',  # 数据库名称,需要自己定义
            'USER': 'root',
            'PASSWORD': '123456',  # 管理员密码
            'HOST': '127.0.0.1',
            'PORT': 3306,
        }
    }
    Copy

关于数据为的SETTING设置

  1. ENGINE

    • 指定数据库存储引擎

    'django.db.backends.mysql'
    'django.db.backends.sqlite3'
    'django.db.backends.oracle'
    'django.db.backends.postgresql'
    Copy
  2. NAME

    • 指定要连接的数据库的名称

    • 'NAME': 'mywebdb'

  3. USER

    • 指定登录到数据库的用户名

    • 'USER':'root'

  4. PASSWORD

    • 接数据库的密码。

    • 'PASSWORD':'123456'

  5. HOST

    • 连接数据库时使用哪个主机。

    • 'HOST':'127.0.0.1'

  6. PORT

    • 连接数据库时使用的端口。

    • 'PORT':'3306'

     

模型Models

模型Models

什么是模型

  • 模型是一个Python类,它是由django.db.models.Model派生出的子类。

  • 一个模型类代表数据库中的一张数据表

  • 模型类中每一个类属性都代表数据库中的一个字段。

  • 模型是数据交互的接口,是表示和操作数据库的方法和方式

 

Django的ORM框架

Django的ORM框架

定义:

ORM(Object Relational Mapping)即对象关系映射,它是一种程序技术,它允许你使用类和对象对数据库进行操作,从而避免通过SQL语句操作数据库

作用:

  1. 建立模型类和表之间的对应关系,允许我们通过面向对象的方式来操作数据库。

  2. 根据设计的模型类生成数据库中的表格。

  3. 通过简单的配置就可以进行数据库的切换。

优点:

只需要面向对象编程, 不需要面向数据库编写代码.

  • 对数据库的操作都转化成对类属性和方法的操作.

  • 不用编写各种数据库的sql语句.

实现了数据模型与数据库的解耦, 屏蔽了不同数据库操作上的差异.

  • 不在关注用的是mysql、oracle...等数据库的内部细节.

  • 通过简单的配置就可以轻松更换数据库, 而不需要修改代码

缺点

  • 对于复杂业务,使用成本较高

  • 根据对象的操作转换成SQL语句,根据查询的结果转化成对象, 在映射过程中有性能损失.

映射图

映射图

 

模型示例

此示例为添加一个 bookstore_book 数据表来存放图书馆中书目信息

  1. 添加一个 bookstoreapp python3 manage.py startapp bookstore

  2. 添加模型类并注册app

    # 模型类代码示例
    # file : bookstore/models.py
    from django.db import models
    
    class Book(models.Model): 
        title = models.CharField("书名", max_length=50, default='')
        price = models.DecimalField('定价', max_digits=7, decimal_places=2, default=0.0)
    Copy
    # 注册app
    # file : setting.py
    INSTALLED_APPS = [
        ...
        'bookstore',
    ]
    Copy
  3. 数据库迁移

    • 迁移是Django同步您对模型所做更改(添加字段,删除模型等) 到您的数据库模式的方式

      1. 生成或更新迁移文件

        将每个应用下的models.py文件生成一个中间文件,并保存在migrations文件夹中

        python3 manage.py makemigrations

      2. 执行迁移脚本程序

        执行迁移程序实现迁移。将每个应用下的migrations目录中的中间文件同步回数据库

        python3 manage.py migrate

      注: 每次修改完模型类再对服务程序运行之前都需要做以上两步迁移操作。

 

模型类

模型类-创建

模型类需继承自django.db.models.Model

Models的语法规范

from django.db import models

class 模型类名(models.Model):
    字段名 = models.字段类型(字段选项)
Copy
  • 模型类的类名是数据表名的一部分,建议类名首字母大写

  • 类属性名,此名称将作为数据表的字段名

  • 字段类型用来映射到数据表中的字段的类型

  • 字段选项为这些字段提供附加的参数信息

 

创建模型类流程

创建模型类流程

  1. 创建应用

  2. 在应用下的 models.py 中编写模型类

    from django.db import models
    
    class 模型类名(models.Model):
        字段名 = models.字段类型(字段选项)
    Copy
  3. 迁移同步 makemigrations & migrate

任何关于表结构的修改,务必在对应模型类上修改

例:为bookstore_book表 添加一个 名为 info 的字段varchar(100)

解决方案 ->

  • 模型类中添加 对应 类属性

  • 执行数据库迁移

 

字符类型

字符类型

  1. BooleanField()

    • 数据库类型:tinyint(1)

    • 编程语言中:使用True或False来表示值

    • 在数据库中:使用1或0来表示具体的值

  2. CharField()

    • 数据库类型:varchar

    • 注意:

      • 必须要指定max_length参数值

  3. DateField()

    • 数据库类型:date

    • 作用:表示日期

    • 参数:

      • auto_now: 每次保存对象时,自动设置该字段为当前时间(取值:True/False)。

      • auto_now_add: 当对象第一次被创建时自动设置当前时间(取值:True/False)。

      • default: 设置当前时间(取值:字符串格式时间如: '2019-6-1')。

      • 以上三个参数只能多选一

  4. DateTimeField()

    • 数据库类型:datetime(6)

    • 作用:表示日期和时间

    • 参数同DateField

  5. DecimalField()

    • 数据库类型:decimal(x,y)

    • 编程语言中:使用小数表示该列的值

    • 在数据库中:使用小数

    • 参数:

      • max_digits: 位数总数,包括小数点后的位数。 该值必须大于等于decimal_places.

      • decimal_places: 小数点后的数字数量

    • 示例:

      money=models.DecimalField(
          max_digits=7,
          decimal_places=2,
          default=0.0
          )
      Copy
  6. FloatField()

    • 数据库类型:double

    • 编程语言中和数据库中都使用小数表示值

  7. EmailField()

    • 数据库类型:varchar

    • 编程语言和数据库中使用字符串

  8. IntegerField()

    • 数据库类型:int

    • 编程语言和数据库中使用整数

  9. URLField()

    • 数据库类型:varchar(200)

    • 编程语言和数据库中使用字符串

  10. ImageField()

    • 数据库类型:varchar(100)

    • 作用:在数据库中为了保存图片的路径

    • 编程语言和数据库中使用字符串

  11. TextField()

    • 数据库类型:longtext

    • 作用:表示不定长的字符数据

参考文档 https://docs.djangoproject.com/en/2.2/ref/models/fields/#field-types

 

创建模型类

创建模型类

bookstore/models.py 应用中 添加 一个模型类

Author - 作者

  • name - CharField 姓名 长度最大11

  • age - IntergerField 年龄

  • email - EmailField 邮箱

 

字段选项

字段选项

  • 字段选项, 指定创建的列的额外的信息

  • 允许出现多个字段选项,多个选项之间使用,隔开

  • primary_key

    • 如果设置为True,表示该列为主键,如果指定一个字段为主键,则此数库表不会创建id字段

  • blank

    • 设置为True时,字段可以为空。设置为False时,字段是必须填写的。

  • null

    • 如果设置为True,表示该列值允许为空。

    • 默认为False,如果此选项为False建议加入default选项来设置默认值

  • default

    • 设置所在列的默认值,如果字段选项null=False建议添加此项

  • db_index

    • 如果设置为True,表示为该列增加索引

  • unique

    • 如果设置为True,表示该字段在数据库中的值必须是唯一(不能重复出现的)

  • db_column

    • 指定列的名称,如果不指定的话则采用属性名作为列名

  • verbose_name

    • 设置此字段在admin界面上的显示名称。

  • 示例:

    # 创建一个属性,表示用户名称,长度30个字符,必须是唯一的,不能为空,添加索引
    name = models.CharField(max_length=30, unique=True, null=False, db_index=True)
    Copy

    文档参见:https://docs.djangoproject.com/en/2.2/ref/models/fields/#field-options

    好习惯: 修改过 字段选项 【添加或更改】均要执行 makemigrations & migrate

     

Meta内部类

Meta内部类

  • 使用内部 Meta类 来给模型赋予属性,Meta类下有很多内建的类属性,可对模型类做一些控制

  • 示例:

    # file : bookstore/models.py
    
    from django.db import models
    
    class Book(models.Model): 
        title = models.CharField("书名", max_length=50, default='')
        price = models.DecimalField('定价', max_digits=7, decimal_places=2, default=0.0)
    
        class Meta:
            db_table = 'book'  #可改变当前模型类对应的表名
    Copy

修改模型类

1. 模型类 - Book   表名 book
  title - CharField(50)  - 书名  唯一
  pub - CharField(100)  - 出版社 非空
  price - DecimalField - 图书定价  总位7/小数点2位
  market_price - 图书零售价  总位7/小数点2位 

2. 模型类 - Author 表名 author 
  name - CharField(11)  - 姓名 非空
  age - IntegerField - 年龄 默认值为1
  email - EmailField - 邮箱 允许为空
Copy

 

数据库的迁移错误处理方法

数据库的迁移错误处理方法

当执行 $ python3 manage.py makemigrations 出现如下迁移错误时的处理方法

  • 错误信息

    You are trying to add a non-nullable field 'des' to book without a default; we can't do that (the database needs something to populate existing rows).
    Please select a fix:
     1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
     2) Quit, and let me add a default in models.py
    Select an option:
    Copy
  • 翻译为中文如下:

    您试图添加一个非空字段'des'来预订没有默认;我们不能这样做(数据库需要填充现有行)
    请选择修复:
    1)现在提供一次性默认值(将对所有现有行设置此列的空值)
    2)退出,让我在models.py中添加一个默认值
    选择一个选项:
    Copy
  • 错误原因

    • 当对模型类新添加一个字段时可出现该错误

    • 原理是 添加新字段后,数据库不知道原来已有数据对于新建字段该如何赋值,所以新增字段时,务必要添加default默认值。

  • 处理方法:

    1. 选择1 则会进入到shell中,手动输入一个默认值

    2. 退出当前生成迁移文件的过程,自己去修改models.py, 新增加一个default=XXX 的缺省值(推荐使用)

  • 数据库的迁移文件混乱的解决办法

    1. 删除 所有 migrations 里所有的 000?*XXXX.py (__init__.py除外)

    2. 删除 数据库

      • sql> drop database mywebdb;

    3. 重新创建 数据库

      • sql> create datebase mywebdb default charset...;

    4. 重新生成migrations里所有的 000?_XXXX.py

      • python3 manage.py makemigrations

    5. 重新更新数据库

      • python3 manage.py migrate

 

数据库的基本操作

数据库的基本操作

  • 基本操作包括增删改查操作,即(CRUD操作)

  • CRUD是指在做计算处理时的增加(Create)、读取查询(Read)、更新(Update)和删除(Delete)

ORM CRUD 核心 -> 模型类.管理器对象

管理器对象

  • 每个继承自 models.Model 的模型类,都会有一个 objects 对象被同样继承下来。这个对象叫管理器对象

  • 数据库的增删改查可以通过模型的管理器实现

    class MyModel(models.Model):
        ...
    MyModel.objects.create(...) # objects 是管理器对象
    Copy

 

Django Shell

Django Shell

  • Django提供了一个交互式的操作项目叫 Django Shell 它能够在交互模式用项目工程的代码执行相应的操作

  • 利用 Django Shell 可以代替编写View的代码来进行直接操作

  • Django Shell 下只能进行简单的操作,不能运行远程调式

  • 启动方式:

    $ python3 manage.py shell
    Copy

 

增加操作

增加操作

  • Django 使用一种直观的方式把数据库表中的数据表示成Python 对象

  • 创建数据中每一条记录就是创建一个数据对象

    1. MyModel.objects.create(属性1=值1, 属性2=值1,...)

      • 成功: 返回创建好的实体对象

      • 失败: 抛出异常

    2. 创建 MyModel 实例对象,并调用 save()进行保存

      obj = MyModel(属性=值,属性=值)
      obj.属性 = 值
      obj.save()
      Copy

练习

在 bookstore/models.py 应用中添加两个model类
1. Book - 图书
    1. title - CharField 书名,非空,唯一
    2. pub - CharField 出版社,字符串,非空
    3. price - DecimalField 图书定价 总长6位/小数点2位
    4. market_price - 图书零售价 总长6位/小数点2位
2. Author - 作者
    1. name - CharField 姓名,非空
    2. age - IntegerField, 年龄,非空,缺省值为1
    3. email - EmailField, 邮箱,允许为空
Copy

然后用Django Shell添加如下数据

图书信息

书名定价零售价出版社
Python 20.00 25.00 清华大学出版社
Django 70.00 75.00 清华大学出版社
JQuery 90.00 85.00 机械工业出版社
Linux 80.00 65.00 机械工业出版社
HTML5 90.00 105.00 清华大学出版社

作者信息:

姓名年龄性别
王老师 28 wangweichao@tedu.cn
吕老师 31 lvze@tedu.cn
祁老师 30 qitx@tedu.cn

 

查询操作

查询操作

数据库的查询需要使用 管理器对象 进行

通过 MyModel.objects管理器方法调用查询方法

方法说明
all() 查询全部记录,返回QuerySet查询对象
get() 查询符合条件的单一记录
filter() 查询符合条件的多条记录
exclude() 查询符合条件之外的全部记录
...  

 

查询方法

查询方法

1. all()方法

  • 方法: all()

  • 用法: MyModel.objects.all()

  • 作用: 查询MyModel实体中所有的数据

  • 等同于 select * from tabel

  • 返回值: QuerySet容器对象,内部存放 MyModel 实例

  • 示例:

      from bookstore.models import Book
      books = Book.objects.all()
      for book in books:
          print("书名", book.title, '出版社:', book.pub)
    Copy

在模型类中定义 def __str__(self): 方法可以自定义默认的字符串

class Book(models.Model):
    title = ...
    def __str__(self):
        return "书名: %s, 出版社: %s, 定价: %s" % (self.title, self.pub, self.price)
Copy

 

2. 查询返回指定列(字典表示)

  • 方法: values('列1', '列2')

  • 用法: MyModel.objects.values(...)

  • 作用: 查询部分列的数据并返回

    • select 列1,列2 from xxx

  • 返回值: QuerySet

    • 返回查询结果容器,容器内存字典,每个字典代表一条数据,

    • 格式为: {'列1': 值1, '列2': 值2}

  • 示例:

      from bookstore.models import Book
    
      books = Book.objects.values("title", "pub")
    
      for book in books:
          print("书名", book["title"], '出版社:', book['pub'])
          print("book=", book)
    Copy

3. 查询返回指定列(元组表示)

  • 方法:values_list('列1','列2')

  • 用法:MyModel.objects.values_list(...)

  • 作用: 返回元组形式的查询结果

  • 返回值: QuerySet容器对象,内部存放 元组

    • 会将查询出来的数据封装到元组中,再封装到查询集合QuerySet

  • 示例:

      from bookstore.models import Book
    
      books = Book.objects.values_list("title", "pub")
    
      for book in books:
          print("书名", book[0], '出版社:', book[1])
          print("book=", book)  # ('Python', '清华大学出版社')...
    Copy

4. 排序查询

  • 方法:order_by

  • 用法:MyModel.objects.order_by('-列','列')

  • 作用:

    • all()方法不同,它会用SQL 语句的ORDER BY 子句对查询结果进行根据某个字段选择性的进行排序

  • 说明:

  • 默认是按照升序排序,降序排序则需要在列前增加'-'表示

  • 示例:

      from bookstore.models import Book
      books = Book.objects.order_by("price")
      for book in books:
      print("书名:", book.title, '定价:', book.price)
    Copy

练习

制作 ‘查看所有书籍’的页面

视图函数 all_book

url http://127.0.0.1:8000/bookstore/all_book

![image-20210911161656084](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911161656084.png)

5. 条件查询 - filter

  • 方法: filter(条件)

  • 语法:

      MyModel.objects.filter(属性1=值1, 属性2=值2)
    Copy
  • 返回值:

    • QuerySet容器对象,内部存放 MyModel 实例

  • 说明:

    • 当多个属性在一起时为"与"关系,即当Books.objects.filter(price=20, pub="清华大学出版社") 返回定价为20 出版社为"清华大学出版社"的全部图书

  • 示例:

      # 查询书中出版社为"清华大学出版社"的图书
      from bookstore.models import Book
    
      books = Book.objects.filter(pub="清华大学出版社")
    
      for book in books:
          print("书名:", book.title)
    
      # 查询Author实体中name为王老师并且age是28岁的
          authors=Author.objects.filter(name='王老师',age=28)
    Copy

6. 条件查询 - exclude

  • 方法: exclude(条件)

  • 语法:

    • MyModel.objects.exclude(条件)

  • 作用:

    • 返回不包含此 条件 的 全部的数据集

  • 示例:

    • 查询 清华大学出版社,定价等于50 以外的全部图书

      books = Book.objects.exclude(pub="清华大学出版社", price=50)
      
      for book in books:
        print(book)
      Copy

7. 条件查询 - get

  • 方法: get(条件)

  • 语法:

    • MyModel.objects.get(条件)

  • 作用:

    • 返回满足条件的唯一一条数据

  • 说明:

    • 该方法只能返回一条数据

    • 查询结果多余一条数据则抛出,Model.MultipleObjectsReturned异常

    • 查询结果如果没有数据则抛出Model.DoesNotExist异常

  • 示例:

      from bookstore.models import Book
    
      book = Book.objects.get(id=1)
      print(book.title)
    Copy

思考?如何做非等值的过滤查询,即 where id > 1

尝试: Book.objects.filter(id > 1) ?

 

查询谓词

查询谓词

定义:做更灵活的条件查询时需要使用查询谓词

说明:每一个查询谓词是一个独立的查询功能

  1. __exact : 等值匹配

     Author.objects.filter(id__exact=1)
     # 等同于select * from author where id = 1
    Copy
  2. __contains : 包含指定值

     Author.objects.filter(name__contains='w')
     # 等同于 select * from author where name like '%w%'
    Copy
  3. __startswith : 以 XXX 开始

  4. __endswith : 以 XXX 结束

  5. __gt : 大于指定值

     Author.objects.filer(age__gt=50)
     # 等同于 select * from author where age > 50
    Copy
  6. __gte : 大于等于

  7. __lt : 小于

  8. __lte : 小于等于

  9. __in : 查找数据是否在指定范围内

    • 示例

      Author.objects.filter(country__in=['中国','日本','韩国'])
      # 等同于 select * from author where country in ('中国','日本','韩国')
      Copy
  10. __range: 查找数据是否在指定的区间范围内

    # 查找年龄在某一区间内的所有作者
    Author.objects.filter(age__range=(35,50))
    # 等同于 SELECT ... WHERE Author BETWEEN 35 and 50;
    Copy

    详细内容参见: https://docs.djangoproject.com/en/2.2/ref/models/querysets/#field-lookups

更新操作

更新操作

1. 更新单个数据

  • 修改单个实体的某些字段值的步骤:

    • 通过 get()得到要修改的实体对象

    • 通过 对象.属性 的方式修改数据

  • 保存

    • 通过 对象.save()保存数据

  • 如:

      from bookstore.models import Book
      abook = Book.objects.get(id=10)
      abook.market_price = "10.5"
      abook.save()
    Copy

2. 批量更新数据

  • 直接调用QuerySet的update(属性=值) 实现批量修改

  • 返回值:更新数据的数量

  • 如:

      # 将id大于3的所有图书价格定为0元
      books = Book.objects.filter(id__gt=3)
      books.update(price=0)
    
      # 将所有书的零售价定为100元
      books = Book.objects.all()
      books.update(market_price=100)
    Copy

练习1: 制作 更新书籍 的页面

![image-20210911161706288](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911161706288.png)

练习2: 制作 更新书籍的页面

点击 ‘查看所有书籍’页面中的 ‘更新’进入更新页面

视图函数 update_book

url http://127.0.0.1:8000/bookstore/update_book/

更新页中显示当前书籍信息,且能对 定价和零售价进行修改

 

删除操作

删除操作

  • 删除记录是指删除数据库中的一条或多条记录

  • 删除单个MyModel对象或删除一个查询结果集(QuerySet)中的全部对象都是调用 delete()方法

1. 单个数据删除

  • 步骤

    1. 查找查询结果对应的一个数据对象

    2. 调用这个数据对象的delete()方法实现删除

  • 示例:

      try:
          auth = Author.objects.get(id=1)
          auth.delete()
      except:
          print(删除失败)
    Copy

2. 批量删除

  • 步骤

    1. 查找查询结果集中满足条件的全部QuerySet查询集合对象

    2. 调用查询集合对象的delete()方法实现删除

  • 示例:

      # 删除全部作者中,年龄大于65的全部信息
      auths = Author.objects.filter(age__gt=65)
      auths.delete()
    Copy

3. 伪删除

  • 通常不会轻易在业务里把数据真正删掉,取而代之的是做伪删除,即在表中添加一个布尔型字段(is_active),默认是True;执行删除时,将欲删除数据的is_active字段置为False

  • 注意:用伪删除时,确保显示数据的地方,均加了is_active=True 的过滤查询

练习:

点击 ‘查看所有书籍’页面中的 ‘删除’;删除当前书籍(伪删除)

视图函数 delete_book

路由 http://127.0.0.1:8000/bookstore/delete?book_id=xx

注意:相关查询获取数据的地方,要过滤出 活跃数据

![image-20210911161719339](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911161719339.png)

 

F对象和Q对象

F对象和Q对象

F 对象

一个F对象代表数据库中某条记录的字段的信息

作用:

  • 通常是对数据库中的字段值在不获取的情况下进行操作

  • 用于类属性(字段)之间的比较。

语法

from django.db.models import F

F("列名")
Copy

示例1 更新Book实例中所有的零售价涨10元

Book.objects.all().update(market_price=F('market_price')+10)
'UPDATE `bookstore_book` SET `market_price` = (`bookstore_book`.`market_price` + 10) 

# 以上做法好于如下代码
books = Book.objects.all()
for book in books:
    book.market_price=book.marget_price+10
    book.save()
Copy

示例2 对数据库中两个字段的值进行比较,列出哪儿些书的零售价高于定价?

from django.db.models import F
from bookstore.models import Book

books = Book.objects.filter(market_price__gt=F('price'))

'SELECT * FROM `bookstore_book` WHERE `bookstore_book`.`market_price` > (`bookstore_book`.`price`)

for book in books:
    print(book.title, '定价:', book.price, '现价:', book.market_price)
Copy

Q 对象

当在获取查询结果集 使用复杂的逻辑或 |、 逻辑非 ~ 等操作时可以借助于 Q对象进行操作

如: 想找出定价低于20元 或 清华大学出版社的全部书,可以写成

Book.objects.filter(Q(price__lt=20)|Q(pub="清华大学出版社"))
Copy

Q对象在 数据包 django.db.models中。需要先导入再使用

  1. 作用

    • 在条件中用来实现除 and(&) 以外的 or(|)not(~)操作

  2. 运算符:

    • & 与操作

    • | 或操作

    • 非操作

  3. 语法

     from django.db.models import Q
     Q(条件1)|Q(条件2)  # 条件1成立或条件2成立
     Q(条件1)&Q(条件2)  # 条件1和条件2同时成立
     Q(条件1)&~Q(条件2)  # 条件1成立且条件2不成立
     ...
    Copy
  4. 示例

     from django.db.models import Q
    
     # 查找清华大学出版社的书或价格低于50的书
     Book.objects.filter(Q(market_price__lt=50) | Q(pub_house='清华大学出版社'))
    
     # 查找不是机械工业出版社的书且价格低于50的书
     Book.objects.filter(Q(market_price__lt=50) & ~Q(pub_house='机械工业出版社'))
    Copy

 

聚合查询

聚合查询

  • 聚合查询是指对一个数据表中的一个字段的数据进行部分或全部进行统计查询,查bookstore_book数据表中的全部书的平均价格,查询所有书的总个数等,都要使用聚合查询

聚合查询 — 整表聚合

  • 不带分组的聚合查询是指导将全部数据进行集中统计查询

  • 聚合函数【需要导入】:

    • 导入方法: from django.db.models import *

    • 聚合函数: Sum, Avg, Count, Max, Min

  • 语法: MyModel.objects.aggregate(结果变量名=聚合函数('列'))

  • 返回结果:

    • 由 结果变量名和值组成的字典

    • 格式为:{"结果变量名": 值}

  • 示例:

      # 得到所有书的平均价格
      from bookstore.models import Book
      from django.db.models import Avg
    
      result = Book.objects.aggregate(myAvg=Avg('price'))
    
      print("平均价格是:", result['myAvg'])
      print("result=", result)  # {"myAvg": 58.2}
    
      # 得到数据表里有多少本书
      from django.db.models import Count
    
      result = Book.objects.aggregate(mycnt=Count('title'))
    
      print("数据记录总个数是:", result['mycnt'])
      print("result=", result)  # {"mycnt": 10}
    Copy

聚合查询 — 分组聚合

  • 分组聚合是指通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。

  • 语法: QuerySet.annotate(结果变量名=聚合函数('列'))

  • 返回值:QuerySet

  • 用法步骤:

    1. 通过先用查询结果MyModel.objects.values 查找查询要分组聚合的列

      • MyModel.objects.values('列1', '列2')

      • 如:

          pub_set = Book.objects.values('pub')
          print(pub_set)  # <QuerySet [{'pub': '清华大学出版社'}, {'pub': '清华大学出版社'}, {'pub_hou {'pub': '机械工业出版社'}, {'pub': '清华大学出版社'}]>
        Copy
    2. 通过返回结果的 QuerySet.annotate方法分组聚合得到分组结果

      • QuerySet.annotate(名=聚合函数('列'))

      • 返回 QuerySet 结果集,内部存储结果的字典

      • 如:

          pub_count_set = pub_set.annotate(myCount=Count('pub'))
          print(pub_count_set)  # <QuerySet [{'pub': '清华大学出版社', 'myCount': 7}, {'pub': '机械工业出版社', 'myCount': 3}]>
        Copy

 

原生数据库操作

原生数据库操作

Django也可以支持 直接用 sql语句的方式通信数据库

查询:使用MyModel.objects.raw()进行 数据库查询操作查询

语法:MyModel.objects.raw(sql语句, 拼接参数)

返回值:RawQuerySet 集合对象 【只支持基础操作,比如循环】

books = models.Book.objects.raw('select * from bookstore_book')

for book in books:
    print(book)
Copy

SQL 注入

使用原生语句时小心 SQL注入

定义:用户通过数据上传,将恶意的sql语句提交给服务器,从而达到攻击效果

案例1: 用户在搜索好友的表单框里 输入 '1 or 1=1'

s1 = Book.objects.raw('select * from bookstore_book where id=%s') %('1 or 1=1')
Copy

攻击结果:可查询出所有用户数据

sql注入防范

错误 -> s1 = Book.objects.raw('select * from bookstore_book where id=%s'%('1 or 1=1'))

正确 -> s2 = Book.objects.raw('select * from bookstore_book where id=%s',['1 or 1=1'])

原生数据库操作 — cursor

完全跨过模型类操作数据库 - 查询/更新/删除

  1. 导入cursor所在的包

    from django.db import connection
    Copy
  2. 用创建cursor类的构造函数创建cursor对象,再使用cursor对象,为保证在出现异常时能释放cursor资源,通常使用with语句进行创建操作

    from django.db import connection
    
    with connection.cursor() as cur:
        cur.execute('执行SQL语句', '拼接参数')
    Copy

示例:

# 用SQL语句将id 为 10的 书的出版社改为 "XXX出版社"
from django.db import connection

with connection.cursor() as cur: 
    cur.execute('update bookstore_book set pub_house="XXX出版社" where id=10;')

with connection.cursor() as cur:
    # 删除 id为1的一条记录
    cur.execute('delete from bookstore_book where id=10;')
Copy

 

关系映射

关系映射

在关系型数据库中,通常不会把所有数据都放在同一张表中,不易于扩展,常见关系映射有:

  1. 一对一映射

    如: 一个身份证对应一个人

  2. 一对多映射

    如: 一个班级可以有多个学生

  3. 多对多映射

    如: 一个学生可以报多个课程,一个课程可以有多个学生学习

 

一对一关联

一对一关联

定义

  • 一对一是表示现实事物间存在的一对一的对应关系。

  • 如:一个家庭只有一个户主,一个男人有一个妻子,一个人有一个唯一的指纹信息等

一对一创建语法

class A(model.Model):
    ...

class B(model.Model):
    属性 = models.OneToOneField(A, on_delete=xxx)
Copy

外键类字段选项

特殊字段参数【必须项】:

  • on_delete

    1. models.CASCADE 级联删除。 Django模拟SQL约束ON DELETE CASCADE的行为,并删除包含ForeignKey的对象。

    2. models.PROTECT 抛出 ProtectedError 以阻止被引用对象的删除;[等同于mysql默认的RESTRICT]

    3. models.SET_NULL 设置ForeignKey null;需要指定null=True

    4. models.SET_DEFAULT 将ForeignKey设置为其默认值;必须设置ForeignKey的默认值。

      更多精彩内容,请参考文档 https://docs.djangoproject.com/en/2.2/ref/models/fields/#foreignkey

其余常用的字段选项【非必须项】;如:

  1. null

  2. unique 等

创建用法示例

1. 创建作家和作家妻子类

# file : oto/models.py
from django.db import models

class Author(models.Model):
    '''作家模型类'''
    name = models.CharField('作家', max_length=50)

class Wife(models.Model):
    '''作家妻子模型类'''
    name = models.CharField("妻子", max_length=50)
    author = models.OneToOneField(Author, on_delete=models.CASCADE)  # 增加一对一属性
Copy

2. 创建一对一的数据记录

from .models import *

# 无外键的模型类[Author]
author1 = Author.objects.create(name='王老师')  

# 有外键的模型内 [Author]
wife1 = Wife.objects.create(name='王夫人', author=author1)  # 关联王老师obj
author2 = Author.objects.create(name='小泽老师')  # 一对一可以没有数据对应的数据
Copy

数据查询

  1. 正向查询: 直接通过关联属性查询即可

     # 通过 wife 找 author
     from .models import Wife
    
     wife = Wife.objects.get(name='王夫人')
     print(wife.name, '的老公是', wife.author.name)
    Copy
  2. 反向查询: 没有外键属性的一方,可以调用反向属性查询到关联的另一方

    • 反向关联属性为实例对象.引用类名(小写),如作家的反向引用为作家对象.wife

    • 当反向引用不存在时,则会触发异常

      # 通过 author.wife 关联属性 找 wife,如果没有对应的wife则触发异常
      author1 = Author.objects.get(name='王老师')
      print(author1.name, '的妻子是', author1.wife.name)
      author2 = Author.objects.get(name='小泽老师')
      
      try:
          print(author2.name, '的妻子是', author2.wife.name)
      except:
          print(author2.name, '还没有妻子')
      Copy

 

一对多关联

一对多关联

定义

  • 一对多是表示现实事物间存在的一对多的对应关系。

  • 如:一个学校有多个班级,一个班级有多个学生, 一本图书只能属于一个出版社,一个出版社允许出版多本图书

一对多需要明确具体角色,在多表上设置外键

一对多创建语法

  • 当一个A类对象可以关联多个B类对象时

class A(model.Model):
    ...

class B(model.Model):
    属性 = models.ForeignKey("一"的模型类, on_delete=xx)
Copy

ForeignKey 必需指定 on_delete模式

创建用法示例

有二个出版社对应五本书的情况.

  1. 清华大学出版社

     

    有书

    1. C++

    2. Java

    3. Python

  2. 北京大学出版社

     

    有书

    1. 西游记

    2. 水浒

1. 模型类创建

# file: otm/models.py
from django.db import models

class Publisher(models.Model):
    '''出版社【一】'''
    name = models.CharField('名称', max_length=50, unique=True)

class Book(models.Model):
    '''书【多】'''
    title = models.CharField('书名', max_length=50)
    publisher = ForeignKey(Publisher, on_delete=models.CASCADE)
Copy

2. 创建数据

# 先创建 '一' ,再创建 '多'
from .models import *

pub1 = Publisher.objects.create(name='清华大学出版社')
Book.objects.create(title='C++', publisher=pub1)
Book.objects.create(title='Java', publisher_id=1)
Copy

数据查询

  1. 正向查询 【通过 Book 查询 Publisher】

     通过 publisher 属性查询即可
     book.publisher
    
     abook = Book.objects.get(id=1)
     print(abook.title, '的出版社是:', abook.publisher.name)
    Copy
  2. 反向查询 【通过 Publisher 查询 对应的所有的 Book】 需要得到反向属性

    Django会在Publisher中增加一个属性来表示对对应的Book们的查询引用
    属性:book_set  等价于 objects
    
    # 通过出版社查询对应的书
    pub1 = Publisher.objects.get(name='清华大学出版社')
    books = pub1.book_set.all()  # 通过book_set 获取pub1对应的多个Book数据对象
    # books = Book.objects.filter(publisher=pub1)  # 也可以采用此方式获取
    print("清华大学出版社的书有:")
    
    for book in books:
       print(book.title)
    Copy

 

 

多对多关联

多对多关联

定义

  • 多对多表达对象之间多对多复杂关系,如: 每个人都有不同的学校(小学,初中,高中,...),每个学校都有不同的学生...

  • mysql中创建多对多需要依赖第三张表来实现

  • Django中无需手动创建第三张表,Django自动完成

多对多语法

  • 在关联的两个类中的任意一个类中,增加:

属性 = models.ManyToManyField(MyModel)
Copy

创建用法示例

  • 一个作者可以出版多本图书

  • 一本图书可以被多名作者同时编写

class Author(models.Model):
    ...

class Book(models.Model):
    ...
    authors = models.ManyToManyField(Author)
Copy

1. 创建模型类

class Author(models.Model):
    '''作家模型类'''
    name = models.CharField('作家', max_length=50)

    def __str__(self):
        return self.name

class Book(models.Model):
    '''书模型类'''
    title = models.CharField('书名', max_length=50)
    authors = models.ManyToManyField(Author)

    def __str__(self):
           return self.title
Copy

2. 创建数据

  1. 方案1 先创建 author 再关联 book

    author1 = Author.objects.create(name='吕老师')
    author2 = Author.objects.create(name='王老师')
    # 吕老师和王老师同时写了一本Python
    book11 = author1.book_set.create(title="Python")
    author2.book_set.add(book11)
    Copy
  2. 方案2 先创建 book 再关联 author

    book = Book.objects.create(title='python1')
    # 郭小闹和吕老师都参与了 python1 的 创作
    author3 = book.authors.create(name='guoxiaonao')
    book.authors.add(author1)
    Copy

数据查询

  1. 正向查询 有多对多属性的对象 查 另一方

    通过 Book 查询对应的所有的 Author

    此时多对多属性 等价于 objects

     book.authors.all() -> 获取 book 对应的所有的author的信息
     book.authors.filter(age__gt=80) -> 获取book对应的作者中年龄大于80岁的作者的信息
    Copy
  2. 反向查询

    通过 Author 查询对应的所有的Book

    利用反向属性 book_set

  3. Django会生成一个反向属性 book_set 用于表示对对应的book的查询对象相关操作

    author.book_set.all()
    author.book_set.filter()
    Copy

 

后台管理

行政后台数据库管理

什么是 Admin 管理后台

  • django 提供了比较完善的后台管理数据库的接口,开发过程中调用和测试使用

  • django 会所有所有已注册的模型类,为这些模型类提开数据管理界面,供开发者使用

![image-20210911161746282](/home/alex/snap/typora/42/.config/Typora/typora-user-images/image-20210911161746282.png)

管理员配置步骤

创建后台管理权限 - 该账号为管理后台最高权限账号

python3 manage.py createsuperuser
复制
  • 可知提示完成注册,参考如下:

    $ python3 manage.py createsuperuser
    Username (leave blank to use 'tarena'): tarena  # 此处输入用户名
    Email address: laowei@tedu.cn  # 此处输入邮箱
    Password: # 此处输入密码(密码要复杂些,否则会提示密码太简单)
    Password (again): # 再次输入重复密码
    Superuser created successfully.
    $
    复制
  • 后台管理的登录地址:http : //127.0.0.1 :8000/ admin/

    用刚注册的管理员账号登陆

注册自定义模型类

想定义自己的模型类也能在/admin后台管理界中显示和管理,需要将自己的类注册到后台管理界面

注册步骤:

  1. 在应用app中的admin.py中导入要管理的模型models类,如:

    from .models import Book
    复制
  2. 调用admin.site.register方法进行注册,如:

    from django.contrib import admin
    
    admin.site.register(自定义模型类)
    复制
  3. 在 bookstore/admin.py 添加如下代码对Book类进行管理

    示例:

    # file: bookstore/admin.py
    from django.contrib import admin
    # Register your models here.
    
    from . import models
    ...
    admin.site.register(models.Book)  # 将Book类注册为可管理页面
    复制

修改自定义模型类的造型样式

  • admin后台管理数据库中对自定义的数据记录都展示为XXXX object类型的记录,不便于阅读和判断

  • 在用户自定义的模型类中可以改写def __str__(self):方法解决问题,例如:

    • 在自定义模型类中改写__str__(self)方法返回显示文字内容:

      class Book(models.Model):
        ...
        def __str__(self):
            return "书名" + self.title
      复制

模型管理器类

作用:

  • 为后台管理界面添加便利操作的新功能。

说明:

  • 后台管理器类须继承自django.contrib.admin里的ModelAdmin

模型管理器的使用方法:

  1. <应用app>/admin.py里定义模型管理器类

     class XXXXManager(admin.ModelAdmin):
         ......
    复制
  2. 绑定注册模型管理器和模型类

     from django.contrib import admin
     from .models import *
     admin.site.register(YYYY, XXXXManager) # 绑定 YYYY 模型类与 管理器类 XXXXManager
    复制
  3. 示例:

      # file : bookstore/admin.py
      from django.contrib import admin
      from .models import Book
    
      class BookManager(admin.ModelAdmin):
          list_display = ['id', 'title', 'price', 'market_price']
    
      admin.site.register(Book, BookManager)
    复制

    进入http://127.0.0.1:8000/admin/bookstore/book/查看显示方式和以前不同

    • 模型管理器类

      ModelAdmin

      中实现的高级管理功能

      1. list_display去控制哪些字段会显示在Admin的修改列表页面中。

      2. list_display_links可以控制list_display中的字段是否应该链接到对象的“更改”页面。

      3. list_filter设置Admin过滤激活修改列表页面列表的器

      4. search_fields设置Admin启用更改列表页面上的搜索框。

      5. list_editable 设置为模型上的字段名称列表,这将允许在更改列表页面上进行编辑。

      6. 其他参见https://docs.djangoproject.com/en/2.2/ref/contrib/admin/

再谈元类

通过Meta内嵌定义类模型类的属性

  • 模型类可以通过定义内部类class Meta来重新定义当前模型类和数据表的一些属性信息

  • 使用格式如下:

      class Book(models.Model):
          title = CharField(....)
    
          class Meta:
              1. db_table = '数据表名'
                  - 该模型所用的数据表的名称。(设置完成后需要立马更新同步数据库)
              2. verbose_name = '单数名'
                  - 给模型对象的一个易于理解的名称(单数),用于显示在/admin管理界面中
              3. verbose_name_plural = '复数名'
                  - 该对象复数形式的名称(复数),用于显示在/admin管理界面中
    复制

练习:

  • Author模型加入后台管理

  • 制作一个AuthorManager管理器类,让后台管理Authors列表中显示作者的ID、姓名、年龄信息

  • 用后台管理程序添加三条Author记录

  • 修改其中一条记录的年龄 -Author

  • 删除最后一条添加的记录 -Author

 

会话保持

会话保持

  • 会话 - 从打开浏览器访问一个网站,到关闭浏览器结束此次访问,称之为一次会话

  • HTTP协议是无状态的,导致会话状态难以保持

  • 试想一下,如果不保持会话状态,在电商网站购物的场景体验?

Cookies和Session就是为了保持会话状态而诞生的两个存储技术

 

cookies

 

Cookies 定义

  • cookies是保存在客户端浏览器上的存储空间

  • Chrome 浏览器 可能通过开发者工具的 Application >> Storage >> Cookies 查看和操作浏览器端所有的 Cookies

  • 火狐浏览器 可能通过开发者工具的 存储 -> Cookie

Cookies 特点

  • cookies 在浏览器上是以键-值对的形式进行存储的,键和值都是以ASCII字符串的形存储(不能是中文字符串)

  • 存储的数据带有生命周期

  • cookies中的数据是按域存储隔离的,不同的域之间无法访问

  • cookies 的内部的数据会在每次访问此网址时都会携带到服务器端,如果cookies过大会降低响应速度

Cookies 的使用

在Django 设置浏览器的COOKIE 必须通过 HttpResponse对象来完成

1. 存储 和 修改

HttpResponse.set_cookie(key, value='', max_age=None, expires=None)
Copy
  • key:cookie的名字

  • value:cookie的值

  • max_age:cookie存活时间,秒为单位

  • expires:具体过期时间

  • 当不指定max_age和expires 时,关闭浏览器时此数据失效

示例

以下示例均在视图函数中调用

2. 添加cookie

# 为浏览器添加键为 my_var1,值为123,过期时间为1个小时的cookie
responds = HttpResponse("已添加 my_var1,值为123")
responds.set_cookie('my_var1', 123, 3600)
return responds
Copy

3. 修改cookie

# 为浏览器添加键为 my_var1,修改值为456,过期时间为2个小时的cookie
responds = HttpResponse("已修改 my_var1,值为456")
responds.set_cookie('my_var1', 456, 3600*2)
return responds
Copy

4. 删除COOKIE

  • HttpResponse.delete_cookie(key)

  • 删除指定的key 的Cookie。 如果key 不存在则什么也不发生。

示例

# 删除浏览器键为 my_var1的cookie
responds = HttpResponse("已删除 my_var1")
responds.delete_cookie('my_var1')
return responds
Copy

5. 获取cookie

  • 通过 request.COOKIES 绑定的字典(dict) 获取客户端的 COOKIES数据

      value = request.COOKIES.get('cookies名', '默认值')
      print("cookies名 = ", value)
    Copy

示例

# 获取浏览器中 my_var变量对应的值
value = request.COOKIES.get('my_var1', '没有值!')
print("cookie my_var1 = ", value)
return HttpResponse("my_var1:" + value)
Copy

 

session

session

Session定义

  • session又名会话控制,是在服务器上开辟一段空间用于保留浏览器和服务器交互时的重要数据

  • 实现方式

    • 使用 session 需要在浏览器客户端启动 cookie,且用在cookie中存储sessionid

    • 每个客户端都可以在服务器端有一个独立的Session

    • 注意:不同的请求者之间不会共享这个数据,与请求者一一对应

session 初始配置

  • settings.py 文件中

  • INSTALLED_APPS 列表中添加:

INSTALLED_APPS = [
    # 启用 sessions 应用
    'django.contrib.sessions',
]
Copy
  • MIDDLEWARE 列表中添加:

MIDDLEWARE = [
    # 启用 Session 中间件
    'django.contrib.sessions.middleware.SessionMiddleware',
]
Copy

session的基本操作

  • session对于象是一个类似于字典的SessionStore类型的对象, 可以用类拟于字典的方式进行操作

  • session 只能够存储能够序列化的数据,如字典,列表等。

  • 保存 session 的值到服务器

    • request.session['KEY'] = VALUE

  • 获取session的值

    • VALUE = request.session['KEY']

    • VALUE = request.session.get('KEY', 缺省值)

  • 删除session的值

    • del request.session['KEY']`

在 settings.py 中有关 session 的设置

  1. SESSION_COOKIE_AGE

    • 作用: 指定sessionid在cookies中的保存时长(默认是2周),如下:

    • SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2

  2. SESSION_EXPIRE_AT_BROWSER_CLOSE = True 设置只要浏览器关闭时,session就失效(默认为False)

注: 当使用session时需要迁移数据库,否则会出现错误

django 原生session 问题:

  1. django_session表是 单表设计; 且该表数据量持续增持【浏览器故意删掉sessionid&过期数据未删除】

  2. 可以每晚执行 python3 manage.py clearsessions 【该命令可删除已过期的session数据】

Cookies 和 session对比

种类存储位置:安全性
Cookies 浏览器中 相对不安全
session 服务器中(mysql) 相对安全

不管Cookies还是Session , 不要存储敏感数据 【密码】

 
posted @ 2022-05-31 10:44  我不知道取什么名字好  阅读(30)  评论(0编辑  收藏  举报