python:Django

Web应用程序的本质:

  1. 接收并解析HTTP请求,获取具体的请求信息
  2. 处理本次HTTP请求,即完成本次请求的业务逻辑处理
  3. 构造并返回处理结果——HTTP响应

Web应用框架就是有助于减轻网页开发时共通性活动的工作负荷,例如许多框架提供数据库访问接口、标准样板以及会话管理等,可提升代码的可再用性。

一、Django介绍

Django 采用了 MVT 的软件设计模式:

  • 模型(Model)
  • 视图(View)
  • 模板(Template)

MTV模式并非Django首创,在其他语言中也有类似的MVC设计模式,甚至可以说django里面的MVT事实上是借鉴了MVC模式衍生出来的。

  • M,Model,模型,是用于完成操作数据库的。
  • V,View,视图,里面的代码就是用于展示给客户端的页面效果。
  • C,Controller,控制器,是一个类或者函数,里面的代码就是用于项目功能逻辑的,一般用于调用模型来获取数据,获取到的数据通过调用视图文件返回给客户端。

而Django中的MTV指的是:

  • M全拼为Model,与MVC中的M功能相同,负责和数据库交互,进行数据处理。
  • V全拼为View,与MVC中的C功能相同,接收请求,进行业务处理,返回应答。
  • T全拼为Template,与MVC中的V功能相同,负责封装构造要返回的html。

MTV模型的工作流程

路由控制器将请求转发给对应的视图函数,完成业务逻辑,视图函数将从model中获取的数据嵌入到template的中模板文件(html)渲染成一个页面字符串,返回给客户端的流程。

所以我们学习Django重点是四个部分:url路由器+MVT 

二、Django的下载与运行

1.Django的下载

# 下载
pip install django==3.2 -i https://pypi.douban.com/simple   # 豆瓣源

# 查看django版本
django-admin --version

2.Django的创建项目及启动运行 

# 1.创建名为myproject的django项目;会在命令执行对应目录下创建myproject文件夹
django-admin startproject myproject

# 2.启动运行django;在pycharm的terminal中输入如下命令;ip:port为空时,默认为本机的8000端口
python manage.py runserver ip:port

注意:酷狗音乐会占用8000端口,注意django与酷狗音乐的端口冲突

访问地址:http://127.0.0.1:8090/ 如下,则表示正确安装了 

注意:runserver默认启动的wsgi.py文件作为web服务器接口 

3.创建应用 

# 创建应用
python manage.py startapp 子应用名称

4.基于IDE 创建Django项目

(1).创建项目及应用

在pycharm里:File-->New Project-->Django下

 (2).启动项目

Edit Configurations编辑IP、端口后,启动即可

进入配置页面

5.Django完整的目录结构

│─ manage.py    # 终端脚本命令,提供了一系列用于生成文件或者目录的命令,也叫脚手架
└─ HelloWorld/        # 主应用开发目录,保存了项目中的所有开发人员编写的代码, 目录是生成项目时指定的
    │- asgi.py      # django3.0以后新增的,用于让django运行在异步编程模式的一个web应用对象
    │- settings.py  # 默认开发配置文件
    │- urls.py      # 路由列表目录,用于绑定视图和url的映射关系
    │- wsgi.py      # wsgi就是项目运行在wsgi服务器时的入口文件
    └- __init__.py
└─ app01         # 子应用
    │- models    # 该应用的模型类模块
    │- views     # 该应用的视图模块
    │- tests     # 该应用的单元测试模块
    │- apps      # 该应用的一些配置,自动生成
    │- admin.py  # 该应用的后台管理系统配置

6.案例:返回一个当前时间页面

7.案例:登录

三、路由控制器

Route路由, 是一种映射关系!路由是把客户端请求的url路径和用户请求的应用程序[这里意指django里面的视图进行绑定映射的一种关系。

注意:请求路径和视图函数不是一对一映射关系!

在django运行中,当客户端发送了一个http请求到服务端,服务端的web服务器则会从http协议中提取url地址, 从程序内部找到项目中添加到urlpatterns里面的所有路由信息的url进行遍历匹配。如果相等或者匹配成功,则调用当前url对象的视图方法。

在给urlpatterns路由列表添加路由的过程中,django一共提供了2个函数给开发者注册路由.

from django.urls import path      # 字符串路由
from django.urls import re_path   # 正则路由,会把url地址看成一个正则模式与客户端的请求url地址进行正则匹配

# path和re_path 使用参数一致.仅仅在url参数和接收参数时写法不一样

1.基本使用

path('login/', login),        # path路由默认会添加^$,该规则等同于path('^login/$', login),

re_path('article/(\d{4})/(\d+)', article_detail),    # 正则匹配的两个参数以位置参数的形式传入article_detail函数
re_path(r'article/(?P<y>\d{4})/(?P<m>\d+)', article_achive),   # 正则匹配的两个参数分别以y,m关键字传参

2.路由分发

from django.urls import include

# 路由分发
path('app01/', include('app01.urls'))

主应用下的urls.py总路由中添加如上的路由分发;在子应用的urls.py路由中像步骤1一样添加即可;

3.路由转发器

4.反向解析

四、视图

django的视图主要有2种,分别是函数视图(FBV)类视图(CBV).

1.请求方式

2.请求对象

django将请求报文中的请求行、首部信息、内容主体封装成 HttpRequest 类中的属性。 除了特殊说明的之外,其他均为只读的。

1.请求方式

print(request.method)

2.请求数据

print(request.GET)      # 一个类似于字典的QueryDict对象,包含 HTTP GET 的所有参数。
print(request.POST)      #一个类似于字典的QueryDict对象,包含请求中的表单数据。post请求参数以urlencoded格式发送时,通过该方式读取比较方便
print(request.body)      # 一个字符串,代表请求报文的请求体的原数据。

注意:request.GET和request.POST返回的dict键值对中,值为一个时,request.GET.get(‘key’)或request.POST.get(‘key’)获取到值;当值为多个时,获取到值中的最后一个;也可以使用request.GET.getlist(‘key’)或request.POST.getlist(‘key’)获取值列表list;

3.请求路径

print(request.path)                  #表示请求的路径组件,不包含get参数
print(request.get_full_path())       #包含get参数路径

4.请求头

print(request.META)     #一个标准的Python 字典,包含所有的HTTP 首部。具体的头部信息取决于客户端和服务器

3.响应对象

响应对象主要有三种形式:

  • HttpResponse()
  • render()
  • redirect()

1.HttpResponse()

Django服务器接收到客户端发送过来的请求后,会将提交上来的这些数据封装成一个 HttpRequest 对象传给视图函数。那么视图函数在处理完相关的逻辑后,也需要返回一个响应给浏览器。而这个响应,我们必须返回 HttpResponseBase 或者他的子类的对象。而 HttpResponse 则是 HttpResponseBase 用得最多的子类。

常用属性:

  • content:返回的内容。
  • status:返回的HTTP响应状态码。
  • content_type:返回的数据的MIME类型,默认为 text/html 。浏览器会根据这个属性,来显示数据。如果是 text/html ,那么就会解析这个字符串,如果 text/plain ,那么就会显示一个纯文本。
  • 设置响应头: response[‘X-Access-Token’] = ‘xxxx’ 。

JsonResponse类:

用来将对象dump成json字符串,然后返回将 json 字符串封装成 Response 对象返回给浏览器。并且他的 Content-Type 是 application/json 。示例代码如下:

from django.http import JsonResponse

def index(request):
    
    return JsonResponse({"title":"三国演义","price":199})

默认情况下 JsonResponse 只能对字典进行 dump ,如果想要对非字典的数据进行 dump ,那么需要给 JsonResponse 传递一个 safe=False 参数。

2.render()

render方法就是将一个模板页面中的模板语法进行渲染,最终渲染成一个html页面作为响应体。

render(request, template_name[, context])
#结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象。

参数: 

/*
 request: 用于生成响应的请求对象。
 template_name:要使用的模板的完整名称,可选的参数
 context:添加到模板上下文的一个字典,
          默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。
          */

3.redirect()

参数可以是:

  • 一个绝对的或相对的URL, 将原封不动的作为重定向的位置.
  • 一个url的别名: 可以使用reverse来反向解析url
def my_view(request):
    ... 
    return redirect("/some/url/")               # 传递要重定向到的一个具体的网址
    return redirect("http://www.baidu.com")      # 或重定向到一个完整网址

传递一个视图的名称:

def my_view(request):
    ...
    return redirect(reverse("url的别名")) 

 APPEND_SLASH的实现就是基于redirect

4.登录验证案例

五、模板语法

模板引擎是一种可以让开发者把服务端数据填充到html网页中完成渲染效果的技术。它实现了把前端代码和服务端代码分离的作用,让项目中的业务逻辑代码和数据表现代码分离,让前端开发者和服务端开发者可以更好的完成协同开发。

  • 静态网页:页面上的数据都是写死的,万年不变
  • 动态网页:页面上的数据是从后端动态获取的(比如后端获取当前时间;后端获取数据库数据然后传递给前端页面)

Django框架中内置了web开发领域非常出名的一个DjangoTemplate模板引擎(DTL)。

要在django框架中使用模板引擎把视图中的数据更好的展示给客户端,需要完成3个步骤:

  1. 在项目配置文件中指定保存模板文件的模板目录。一般模板目录都是设置在项目根目录或者主应用目录下。
  2. 在视图中基于django提供的渲染函数绑定模板文件和需要展示的数据变量
  3. 在模板目录下创建对应的模板文件,并根据模板引擎内置的模板语法,填写输出视图传递过来的数据。

配置模板目录:在当前项目根目录下创建了模板目录templates. 然后在settings.py, 模板相关配置,找到TEMPLATES配置项,填写DIRS设置模板目录。

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates']
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

1.简单案例

2.render函数内部本质

3.模板语法

1.变量渲染之深度查询

视图函数传给DTL模板,列表list或字典dict的变量时,通过点.实现深度查询;

    <p>列表成员</p>
    <p>{{ lve }}</p>
    <p>{{ lve.0 }}</p>
    <p>{{ lve | last }}</p>

    <p>字典成员</p>
    <p>id={{ bookinfo.id }}</p>
    <p>price={{ bookinfo.price }}</p>
    <p>name={{ bookinfo.name }}</p>

2.变量渲染之内置过滤器

语法:

{{obj|过滤器名称:过滤器参数}}

内置过滤器:

过滤器用法代码
last获取列表/元组的最后一个成员{{liast | last}}
first获取列表/元组的第一个成员{{list|first}}
length获取数据的长度{{list | length}}
defualt当变量没有值的情况下, 系统输出默认值,{{str|default=“默认值”}}
safe让系统不要对内容中的html代码进行实体转义{{htmlcontent| safe}}
upper字母转换成大写{{str | upper}}
lower字母转换成小写{{str | lower}}
title每个单词首字母转换成大写{{str | title}}
date日期时间格式转换{{ value| date:"D d M Y" }}
cut从内容中截取掉同样字符的内容{{content | cut:“hello”}}
list把内容转换成列表格式{{content | list}}
add加法{{num| add}}
filesizeformat把文件大小的数值转换成单位表示{{filesize | filesizeformat}}
join按指定字符拼接内容{{list| join("-")}}
random随机提取某个成员{list | random}}
slice按切片提取成员{{list | slice:":-2"}}
truncatechars按字符长度截取内容{{content | truncatechars:30}}
truncatewords按单词长度截取内容同上

过滤器的使用:

<p>当前书籍: {{ books|default:'没有符合条件的书籍' }}</p>
<p>文件大小: {{ fileSize|filesizeformat }}</p>
<p>出生日期: {{ birthday|date:'Y-m-d H:i:s' }}</p>
<p>字符串截取: {{ s|truncatechars:8 }}</p>
<p>字符串转义: {{ content|safe }}</p>
<p>求值计算: {{ num|add:20 }}</p>

3.自定义过滤器

4.标签

1.if标签

{% if num == 100 %}
<p>num的值为100</p>
{% elif num > 100 %}
<p>num的值大于100</p>
{% else %}
<p>num小于100</p>
{% endif %}

2.for标签

{% for i in books %}
<p>书名:{{ i.name }} 价格:{{ i.price }}</p>
{% endfor %}

循环中, 模板引擎提供的forloop对象,用于给开发者获取循环次数或者判断循环过程的.

属性描述
forloop.counter显示循环的次数,从1开始
forloop.counter0显示循环的次数,从0开始
forloop.revcounter0倒数显示循环的次数,从0开始
forloop.revcounter倒数显示循环的次数,从1开始
forloop.first判断如果本次是循环的第一次,则结果为True
forloop.last判断如果本次是循环的最后一次,则结果为True
forloop.parentloop在嵌套循环中,指向当前循环的上级循环

5.模板嵌套继承

传统的模板分离技术,依靠{% include “模板文件名”%}实现,这种方式,虽然达到了页面代码复用的效果,但是由此也会带来大量的碎片化模板,导致维护模板的成本上升.因此, Django框架中除了提供这种模板分离技术以外,还并行的提供了 模板继承给开发者.

{% include "模板文件名"%}  # 模板嵌入
{% extends "base.html" %} # 模板继承 

1.继承父模板的公共内容

{% extends 'app02/base.html' %}       # 继承base.html父模板文件

2.个性展示不同于父模板的内容 

在父模板中添加block,如下:block名称为block_name,和默认内容;

{% block block_name %}          #父模板base.html中名为block_name的内容;
    block_default_content
{% endblock %}

在子模板temp.html文件中,添加如下:

{% extends 'app02/base.html' %}    # 继承父模板base.html的内容

{% block block_name %}             #重写父模板base.html中block_name的内容,若没有重写,则展示父模板的内容
{{ block.super }}                   # 展示父模板base.html的block_name的内容
temp
{% endblock %}
  • 如果你在模版中使用 {% extends %} 标签,它必须是模版中的第一个标签。其他的任何情况下,模版继承都将无法工作。
  • 在base模版中设置越多的 {% block %} 标签越好。请记住,子模版不必定义全部父模版中的blocks,所以,你可以在大多数blocks中填充合理的默认内容,然后,只定义你需要的那一个。多一点钩子总比少一点好。
  • 为了更好的可读性,你也可以给你的 {% endblock %} 标签一个 名字 。例如:{``% block content``%``}``...``{``% endblock content``%``},在大型模版中,这个方法帮你清楚的看到哪一个  {% block %} 标签被关闭了。
  • 不能在一个模版中定义多个相同名字的 block 标签。

4.静态文件 

六、模型层(ORM)

Django中内嵌了ORM框架,不需要直接编写SQL语句进行数据库操作,而是通过定义模型类,操作模型类来完成对数据库中表的增删改查和创建等操作。

  • O是object,也就类对象的意思。
  • R是relation,翻译成中文是关系,也就是关系数据库中数据表的意思。
  • M是mapping,是映射的意思。

映射

  • 类:sql语句table表
  • 类成员变量:table表中的字段、类型和约束
  • 类对象:sql表的表记录

ORM的优点

  • 数据模型类都在一个地方定义,更容易更新和维护,也利于重用代码。

  • ORM 有现成的工具,很多功能都可以自动完成,比如数据消除、预处理、事务等等。

  • 它迫使你使用 MVC 架构,ORM 就是天然的 Model,最终使代码更清晰。

  • 基于 ORM 的业务代码比较简单,代码量少,语义性好,容易理解。

  • 新手对于复杂业务容易写出性能不佳的 SQL,有了ORM不必编写复杂的SQL语句, 只需要通过操作模型对象即可同步修改数据表中的数据.

  • 开发中应用ORM将来如果要切换数据库.只需要切换ORM底层对接数据库的驱动【修改配置文件的连接地址即可】

ORM的缺点

  • ORM 库不是轻量级工具,需要花很多精力学习和设置,甚至不同的框架,会存在不同操作的ORM。
  • 对于复杂的业务查询,ORM表达起来比原生的SQL要更加困难和复杂。
  • ORM操作数据库的性能要比使用原生的SQL差。
  • ORM 抽象掉了数据库层,开发者无法了解底层的数据库操作,也无法定制一些特殊的 SQL。【自己使用pymysql另外操作即可,用了ORM并不表示当前项目不能使用别的数据库操作工具了。】

1.配置数据库连接

在settings.py中保存了数据库的连接配置信息,Django默认初始配置使用sqlite数据库。

1.安装pymysql

2.在Django的工程同名子目录的__init__.py文件中添加如下语句

from pymysql import install_as_MySQLdb
install_as_MySQLdb() # 让pymysql以MySQLDB的运行模式和Django的ORM对接运行

作用是让Django的ORM能以mysqldb的方式来调用PyMySQL。

3.修改DATABASES配置信息

在Django同名子目录下settings.py文件中修改DATABASE配置信息

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': '127.0.0.1',  # 数据库主机
        'PORT': 3306,  # 数据库端口
        'USER': 'root',  # 数据库用户名
        'PASSWORD': '123',  # 数据库用户密码
        'NAME': 'student'  # 数据库名字
    }
}

4.在mysql中创建数据库

create database student; # mysql8.0默认就是utf8mb4;
create database student default charset=utf8mb4; # mysql8.0之前的版本

5.注意3: 如果想打印orm转换过程中的sql,需要在settings中进行如下配置:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
} 

2.定义模型类

  • 模型类被定义在"子应用/models.py"文件中。
  • 模型类必须直接或者间接继承自django.db.models.Model类。

在models.py中,定义模型类

from django.db import models
from datetime import datetime

# 模型类必须要直接或者间接继承于 models.Model
class BaseModel(models.Model):
    """公共模型[公共方法和公共字段]"""
    # created_time = models.IntegerField(default=0, verbose_name="创建时间")
    created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    # auto_now_add 当数据添加时设置当前时间为默认值
    # auto_now= 当数据添加/更新时, 设置当前时间为默认值
    updated_time = models.DateTimeField(auto_now=True)
    class Meta(object):
        abstract = True # 设置当前模型为抽象模型, 当系统运行时, 不会认为这是一个数据表对应的模型.

class Student(BaseModel):
    """Student模型类"""
    #1. 字段[数据库表字段对应]
    SEX_CHOICES = (
        (0,"女"),
        (1,"男"),
        (2,"保密"),
    )

    # 字段名 = models.数据类型(约束选项1,约束选项2, verbose_name="注释")
    # SQL: id bigint primary_key auto_increment not null comment="主键",
    # id = models.AutoField(primary_key=True, null=False, verbose_name="主键") # django会自动在创建数据表的时候生成id主键/还设置了一个调用别名 pk

    # SQL: name varchar(20) not null comment="姓名"
    # SQL: key(name),
    name = models.CharField(max_length=20, db_index=True, verbose_name="姓名" )

    # SQL: age smallint not null comment="年龄"
    age = models.SmallIntegerField(verbose_name="年龄")

    # SQL: sex tinyint not null comment="性别"
    # sex = models.BooleanField(verbose_name="性别")
    sex = models.SmallIntegerField(choices=SEX_CHOICES, default=2)

    # SQL: class varchar(5) not null comment="班级"
    # SQL: key(class)
    classmate = models.CharField(db_column="class", max_length=5, db_index=True, verbose_name="班级")
    # SQL: description longtext default "" not null comment="个性签名"
    description = models.TextField(default="", verbose_name="个性签名")

    #2. 数据表结构信息
    class Meta:
        db_table = 'tb_student'  # 指明数据库表名,如果没有指定表明,则默认为子应用目录名_模型名称,例如: users_student
        verbose_name = '学生信息表'  # 在admin站点中显示的名称
        verbose_name_plural = verbose_name  # 显示的复数名称

    #3. 自定义数据库操作方法
    def __str__(self):
        """定义每个数据对象的显示信息"""
        return "<User %s>" % self.name

1.数据库表名

模型类如果未指明表名db_table,Django默认以 小写app应用名_小写模型类名 为数据库表名。

可通过db_table 指明数据库表名。

2.关于主键

django会为表创建自动增长的主键列id,每个模型只能有一个主键列。

如果使用选项设置某个字段的约束属性为主键列(primary_key)后,django不会再创建自动增长的主键列。

3.属性命名机制

  • 不能是python的保留关键字。
  • 不允许使用连续的2个下划线,这是由django的查询方式决定的。__ 是关键字来的,不能使用!!!
  • 定义属性时需要指定字段类型,通过字段类型的参数指定选项,语法如下:
    属性名 = models.字段类型(约束选项, verbose_name="注释")

4.字段类型

类型说明
AutoField自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性
BooleanField布尔字段,值为True或False
NullBooleanField支持Null、True、False三种值
CharField字符串,参数max_length表示最大字符个数,对应mysql中的varchar
TextField大文本字段,一般大段文本(超过4000个字符)才使用。
IntegerField整数
DecimalField十进制浮点数, 参数max_digits表示总位数, 参数decimal_places表示小数位数,常用于表示分数和价格 Decimal(max_digits=7, decimal_places=2) ==> 99999.99~ 0.00
FloatField浮点数
DateField日期参数auto_now表示每次保存对象时,自动设置该字段为当前时间。参数auto_now_add表示当对象第一次被创建时自动设置当前。参数auto_now_add和auto_now是相互排斥的,一起使用会发生错误。
TimeField时间,参数同DateField
DateTimeField日期时间,参数同DateField
FileField上传文件字段,django在文件字段中内置了文件上传保存类, django可以通过模型的字段存储自动保存上传文件, 但是, 在数据库中本质上保存的仅仅是文件在项目中的存储路径!!
ImageField继承于FileField,对上传的内容进行校验,确保是有效的图片

5.约束选项

选项说明
null如果为True,表示允许为空,默认值是False。相当于python的None
blank如果为True,则该字段允许为空白,默认值是False。 相当于python的空字符串,“”
db_column字段的名称,如果未指定,则使用属性的名称。
db_index若值为True, 则在表中会为此字段创建索引,默认值是False。 相当于SQL语句中的key
default默认值,当不填写数据时,使用该选项的值作为数据的默认值。
primary_key如果为True,则该字段会成为模型的主键,默认值是False,一般不用设置,系统默认设置。
unique如果为True,则该字段在表中必须有唯一值,默认值是False。相当于SQL语句中的unique

注意:null是数据库范畴的概念,blank是表单验证范畴的 

6.外键

3.数据迁移

将模型类定义表架构的代码转换成SQL同步到数据库中,这个过程就是数据迁移。django中的数据迁移,就是一个类,这个类提供了一系列的终端命令,帮我们完成数据迁移的工作。

1.生成迁移文件

所谓的迁移文件, 是类似模型类的迁移类,主要是描述了数据表结构的类文件.

python manage.py makemigrations

2.同步到数据库中

python manage.py migrate

补充:在django内部提供了一系列的功能,这些功能也会使用到数据库,所以在项目搭建以后第一次数据迁移的时候,会看到django项目中其他的数据表被创建了。其中就有一个django内置的admin站点管理。

# admin站点默认是开启状态的,我们可以通过http://127.0.0.1:8000/admin
# 这个站点必须有个管理员账号登录,所以我们可以在第一次数据迁移,有了数据表以后,就可以通过以下终端命令来创建一个超级管理员账号。
python manage.py createsuperuser

4.数据库基本操作

1.添加记录

# 方式1:save方法
# 通过创建模型类对象,执行对象的save()方法保存到数据库中。
student = Student(name='张三', age=12, classmate='s12')
student.save()     # 调用save方法会转换成sql的insert语句
print(student.id)

# 方式2(推荐)
# 通过模型类.objects.create()保存,返回生成的模型类对象。
student = Student.objects.create(name='李四', age=14, classmate='s22')
print(student.id)

2.基础查询 

ORM中针对查询结果的限制,提供了一个查询集[QuerySet].这个QuerySet,是ORM中针对查询结果进行保存数据的一个类型,我们可以通过了解这个QuerySet进行使用,达到查询优化,或者限制查询结果数量的作用。

1.all()

查询所有对象,返回queryset对象。查询集,也称查询结果集、QuerySet,表示从数据库中获取的对象集合。

students = Student.objects.all()
print("students:",students)

2.filter() 

筛选条件相匹配的对象,返回queryset对象。

# 查询所有的女生
students = Student.objects.filter(sex=0)
print(students)

3.get()

返回与所给筛选条件相匹配的对象,返回结果有且只有一个, 如果符合筛选条件的对象超过一个或者没有都会抛出错误。

student = Student.objects.get(pk=1)
print(student)
print(student.description)
get使用过程中的注意点:get是根据条件返回多个结果或者没有结果,都会报错
try:
    student = Student.objects.get(name="刘德华")
    print(student)
    print(student.description)
except Student.MultipleObjectsReturned:
    print("查询得到多个结果!")
except Student.DoesNotExist:
    print("查询结果不存在!")

4.first()、last()

分别为查询集的第一条和最后一条记录;

# 没有结果返回none,如果有多个结果,则返回模型对象
students = Student.objects.all()
# print(students.name)
print(students[0].name)
stu01 = Student.objects.first()
stu02 = Student.objects.last()

print(stu01.name)
print(stu02.name)

5.exclude()

筛选条件不匹配的对象,返回queryset对象。

students = Student.objects.exclude(name='张三')
print(students)

6.order_by()

对查询结果排序

# order_by("字段")  # 按指定字段正序显示,相当于 asc  从小到大
# order_by("-字段") # 按字段倒序排列,相当于 desc 从大到小
# order_by("第一排序","第二排序",...)

# 查询所有的男学生按年龄从高到低展示
# students = Student.objects.all().order_by("-age","-id")
students = Student.objects.filter(sex=1).order_by("-age", "-id")
print(students)

7.count()

查询集中对象的个数

# 查询所有男生的个数
count = Student.objects.filter(sex=1).count()
print(count)

8.exists()

判断查询集中是否有数据,如果有则返回True,没有则返回False

# 查询Student表中是否存在学生
print(Student.objects.exists())

9.values()、values_list()

  • value()把结果集中的模型对象转换成字典,并可以设置转换的字段列表,达到减少内存损耗,提高性能
  • |values_list(): 把结果集中的模型对象转换成列表,并可以设置转换的字段列表(元祖),达到减少内存损耗,提高性能
# values 把查询结果中模型对象转换成字典
student_list = Student.objects.filter(classmate="301")
student_list = student_list.order_by("-age")
student_list = student_list.filter(sex=1)
ret1 = student_list.values() # 默认把所有字段全部转换并返回
ret2 = student_list.values("id","name","age") # 可以通过参数设置要转换的字段并返回
ret3 = student_list.values_list() # 默认把所有字段全部转换并返回
ret4 = student_list.values_list("id","name","age") # 可以通过参数设置要转换的字段并返回
print(ret4)
return JsonResponse({},safe=False)

10.distinct()

从返回结果中剔除重复纪录。返回queryset。

# 查询所有学生出现过的年龄
print(Student.objects.values("age").distinct())

3.模糊查询

(1)模糊查询之contains

说明:如果要包含%无需转义,直接写即可。

Student.objects.filter(name__contains='华')

(2)模糊查询之startswith、endswith

Student.objects.filter(name__endswith='文')

注意:以上运算符都区分大小写,在这些运算符前加上i表示不区分大小写,如iexact、icontains、istartswith、iendswith. 

(3)模糊查询之isnull

Student.objects.filter(description__isnull=True)

(4)模糊查询之in

Student.objects.filter(sex__in=[1, 0])

(5)模糊查询之比较查询

  • gt 大于 (greater then)
  • gte 大于等于 (greater then equal)
  • lt 小于 (less then)
  • lte 小于等于 (less then equal)
Student.objects.filter(id__gte=4)

(6)模糊查询之range

Student.objects.filter(age__range=(12, 23))

注意:此处的range()是左闭右闭; 

(7)模糊查询之日期查询

year、month、day、week_day、hour、minute、second:对日期时间类型的属性进行运算。

Student.objects.filter(birthday__year=2021)
Student.objects.filter(birthday__year__gte=2022)
Student.objects.filter(birthday__week_day=1)

(8)exact 

4.进阶查询

1.F查询:用于两个字段之间的比较

from django.db.models import F

student_list = Student.objects.exclude(created_time=F("updated_time"))
print(student_list)

2.Q查询:

多个过滤器逐个调用表示逻辑与关系,同sql语句中where部分的and关键字。

Student.objects.filter(age__gt=20,id__lt=30)
或
Student.filter(age__gt=20).filter(id__lt=30)

如果需要实现逻辑或or的查询,需要使用Q()对象结合|运算符,Q对象被义在django.db.models中。语法如下:

Q(属性名__运算符=值)
Q(属性名__运算符=值) | Q(属性名__运算符=值)

Q对象可以使用&、|连接,&表示逻辑与,|表示逻辑或 

Q对象左边可以使用~操作符,表示非not。但是工作中,我们只会使用Q对象进行或者的操作,只有多种嵌套复杂的查询条件才会使用&和~进行与和非得操作

3.聚合查询

使用aggregate()过滤器调用聚合函数。聚合函数包括:Avg 平均,Count 数量,Max 最大,Min 最小,Sum 求和,被定义在django.db.models中。例:求学生的平均年龄

from django.db.models import Sum,Count,Avg,Max,Min

Student.objects.aggregate(Avg('age'))

注意:aggregate的返回值是一个字典类型,格式如下:

  {'属性名__聚合类小写':值}

使用count时一般不使用aggregate()过滤器。例如:查询学生总数

Student.objects.count() # count函数的返回值是一个数字。

4.分组查询

# select class,avg('age')  from tb_student group by class
Student.objects.values('classmate').annotate(Avg('age'))
Student.objects.values('classmate').annotate(v = Avg('age')   #重命名返回字段名


# SQL原生语句中分组之后可以使用having过滤,在django中并没有提供having对应的方法,但是可以使用filter对分组结果进行过滤
# 所以filter在annotate之前,表示where,在annotate之后代表having
# 同理,values在annotate之前,代表分组的字段,在annotate之后代表数据查询结果返回的字段

5.原生查询

 ret = Student.objects.raw("SELECT id,name,age FROM db_student")  # student 可以是任意一个模型
 # 这样执行获取的结果无法通过QuerySet进行操作读取,只能循环提取
 print(ret,type(ret))
 for item in ret:
    print(item,type(item))

5.修改记录

1.方式1:模型类对象调用save方法

student = Student.objects.filter(name='刘德华').first()
print(student)
student.age = 19
student.classmate = "303"
# save之所以能提供给我们添加数据的同时,还可以更新数据的原因?
# save会找到模型的字段的主键id的值,
# 主键id的值如果是none,则表示当前数据没有被数据库,所以save会自动变成添加操作
# 主键id有值,则表示当前数据在数据库中已经存在,所以save会自动变成更新数据操作
student.save()

2.方式2:模型类.objects.filter().update();会返回受影响得到行数

# update是全局更新,只要符合更新的条件,则全部更新,因此强烈建议加上条件!!!
student = Student.objects.filter(name="赵华",age=22).update(name="刘芙蓉",sex=True)
print(student)

5.删除记录

1.方式1:删除模型类对象

student = Student.objects.get(id=13)
student.delete()

2.方式2:模型类.object.filter().delete()

Student.objects.filter(id=14).delete() 

# 务必写上条件,否则变成了清空表了。Student.objects.filter().delete()

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值