5.ORM模型层--单表查询
ORM模型层--单表查询
1.ORM模型层
ORM是“对象-关系-映射”的简称,orm其实就是将类对象的语法翻译成sql语句的一个引擎
特点:
orm开发效率高 执行效率低
orm迁移数据库方便: 从Mysql -- 迁移到oracle 不需要重写建表语句
数据库迁移(同步)指令
# python manage.py makemigrations
# python manage.py migrate
2.单表查询
创建表
在应用的models.py文件中声明类
from django.db import models
# 表名 -- app01_book 应用_小写表名
class Book(models.Model):
# id = models.AutoField(primary_key=True)
# id int primary key auto_increment
# 生成表时,会自动生成一个id主键字段
title = models.CharField(max_length=32)
# title varchar(32) not null 自动有一个约束不能为空
price = models.IntegerField()
# price int not null
pub_date = models.DateField()
# pub_date date not null
publish = models.CharField(max_length=32)
def __str__(self):
return self.title #查询书籍对象时会返回书籍名称
执行数据库迁移(同步)指令
python manage.py makemigrations
python manage.py migrate
配置连接mysql
第一步: 去mysql中创建库
mysql> create database orm01 charset=utf8mb4; # utf8mb4支持中文 utf8有些生僻字它不支持
第二步:
settings.py文件中进行如下修改
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'orm01', #要连接mysql数据库名称
'HOST': '127.0.0.1', #连接地址--本地连接
'PORT': '3306', #端口号3306
'USER': 'root', #用什么用户连接
'PASSWORD': '123456' #数据库密码
}
}
第三步:
在项目主目录下面的__init__.py
文件中指定连接mysql数据的客户端模块
import pymysql
pymysql.install_as_MySQLdb()
第四步:
执行数据库迁移(同步)指令
python manage.py makemigrations
python manage.py migrate
字段参数介绍
(1)null
如果为True,Django 将用NULL 来在数据库中存储空值。 默认值是 False.
(1)blank
如果为True,该字段允许不填。默认为False。
要注意,这与 null 不同。null纯粹是数据库范畴的,而 blank 是数据验证范畴的。
如果一个字段的blank=True,表单的验证将允许该字段是空值。如果字段的blank=False,该字段就是必填的。
(2)default
字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用,如果你的字段没有设置可以为空,那么将来如果我们后添加一个字段,这个字段就要给一个default值
(3)primary_key
如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True,
Django 就会自动添加一个IntegerField字段做为主键,所以除非你想覆盖默认的主键行为,
否则没必要设置任何一个字段的primary_key=True。
(4)unique
如果该值设置为 True, 这个数据字段的值在整张表中必须是唯一的
(5)db_index
如果db_index=True 则代表着为此字段设置数据库普通索引。
(6)choices
由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,<br>而且这个选择框的选项就是choices 中的选项。
DatetimeField(日期时间)、DateField(日期)、TimeField(时间)这个三个时间字段,都可以设置如下属性。
(7)auto_now_add
配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。
(8)auto_now
配置上auto_now=True,每次更新数据记录的时候会更新该字段,标识这条记录最后一次的修改时间。
13个查询接口(必知必会)
<1> all(): objects控制器或者queryset类型数据调用,查询所有结果,结果是queryset类型
<2> filter(**kwargs): objects控制器或者queryset类型数据调用,它包含了与所给筛选条件相匹配的对象,结果也是queryset类型 Book.objects.filter(title='linux',price=100) #里面的多个条件用逗号分开,并且这几个条件必须都成立,是and的关系,or关系的我们后面再学,直接在这里写是搞不定or的
<3> get(**kwargs): objects控制器或者queryset类型数据调用,返回与所给筛选条件相匹配的对象,不是queryset类型,是行记录对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。捕获异常try。 Book.objects.get(id=1)
两个报错:
查询结果多于1个了: get() returned more than one Book -- it returned 2!
查询结果没有: Book matching query does not exist.
<4> exclude(**kwargs): 排除的意思,它包含了与所给筛选条件不匹配的对象,没有不等于的操作昂,用这个exclude,返回值是queryset类型 Book.objects.exclude(id=6),返回id不等于6的所有的对象,或者在queryset基础上调用,Book.objects.all().exclude(id=6)
<5> order_by(*field): queryset类型的数据来调用,对查询结果排序,默认是按照id来升序排列的,返回值还是queryset类型
models.Book.objects.all().order_by('price','id')
#直接写price,默认是按照price升序排列,按照字段降序排列,就写个负号就行了order_by('-price'),order_by('price','id')是多条件排序,按照price进行升序,price相同的数据,按照id进行升序
<6> reverse(): queryset类型的数据来调用,对查询结果反向排序,返回值还是queryset类型
但是:只对排序之后的数据才能进行翻转:
all_books = models.Book.objects.all().order_by('id').reverse()
<7> count(): queryset类型的数据来调用,返回数据库中匹配查询(QuerySet)的对象数量。
all_books = models.Book.objects.all().count() # 14
<8> first(): queryset类型的数据来调用,返回第一条记录
Book.objects.all()[0] = Book.objects.all().first(),得到的都是model对象,不是queryset类型
<9> last(): queryset类型的数据来调用,返回最后一条记录
<10> exists(): queryset类型的数据来调用,如果QuerySet包含数据,就返回True,否则返回False.
queryset类型数据也有布尔值True和False,但是一般不用它来判断数据库里面是不是有数据,如果有大量的数据,你用它来判断,那么就需要查询出所有的数据,效率太差了,用count或者exists
例:all_books = models.Book.objects.all().exists() #翻译成的sql是SELECT (1) AS `a` FROM `app01_book` LIMIT 1,就是通过limit 1,取一条来看看是不是有数据
<11> values(*field): 用的比较多,queryset类型的数据来调用,返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列,只要是返回的queryset类型,就可以继续链式调用queryset类型的其他的查找方法,其他方法也是一样的。
# all_books = models.Book.objects.values('title', 'price')
all_books = models.Book.objects.all().values('title', 'price')
得到结果:# <QuerySet [{'title': '白金鸽3', 'price': 12}, {'title': '王照', 'price': 3}, ....
<12> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values()返回的是一个字典序列
# all_books = models.Book.objects.values_list('title', 'price')
all_books = models.Book.objects.all().values_list('title', 'price')
得到结果:#<QuerySet [('斗破苍穹', 220), ('赘婿', 22),...]>
<13> distinct():去重,配合values和values_list得到的queryset类型的数据来调用,从返回结果中剔除重复纪录.
不使用values和values_list得到的queryset类型的数据里面是模型类对象,id不同,都是不重复的
all_books = models.Book.objects.values_list('title',).distinct()
基于双下划线的模糊查询
1.Book.objects.filter(price__in=[100,200,300]) #price值等于这三个里面的任意一个的对象
2.Book.objects.filter(price__gt=100) #大于,大于等于是price__gte=100,别写price>100,这种参数不支持
3.Book.objects.filter(price__lt=100) #小于,小于等于是lte=100
示例:
# books = models.Book.objects.filter(price__in=[3,4,5])
4.Book.objects.filter(price__range=[100,200]) #sql的between and,大于等于100,小于等于200
示例:
#books = models.Book.objects.filter(price__range=[3, 9])
5.Book.objects.filter(title__contains="python") #title值中包含python的
6.Book.objects.filter(title__icontains="python") #不区分大小写
7.Book.objects.filter(title__startswith="py") #以什么开头,istartswith 不区分大小写
8.Book.objects.filter(title__endswith="on") #以什么开头,iendswith 不区分大小写
示例:
# books = models.Book.objects.filter(title__contains='py') #包含,区分大小写
9.Book.objects.filter(pub_date__year=2012) #month月份,day日期
示例:
# books = models.Book.objects.filter(pub_date__year='2021') # 年份等于2021年的
# books = models.Book.objects.filter(pub_date__year__gt='2018') # 年份大于2018年的书籍
books = models.Book.objects.filter(pub_date__year='2021', pub_date__month='2') # 查询2021年2月份的所有书籍
# books = models.Book.objects.filter(pub_date__year='2021', pub_date__month='2', pub_date__day='3') # 查询2021年2月3日的所有书籍
books = models.Book.objects.filter(pub_date='2021-2-3') # 查询2021年2月3日的所有书籍
表数据的增删改查
在应用的views.py视图中声明函数,urls.py路由指向视图函数
1.增加
from django.shortcuts import render,HttpResponse
from app01 import models #想操作表先引入models类
import datetime
#表数据的增删改查
def query(request):
#增加
#添加数据方式1:
book_obj = models.Book.objects.create( #objects是Book类的控制器
title='斗破苍穹',
price=220,
# pub_date='2018-05-15', #日期类型数据两种方式:1.字符串
pub_date=datetime.datetime.now(),#日期类型数据两种方式: 2.日期类型数据
publish='py33出版社',
)
print(book_obj) # Book object 模型类对象,一个模型类对象表示一条记录
#添加数据方式2:
new_obj = models.Book( #实例化类对象
title='赘婿',
price=45,
pub_date='2020-1-12',
publish='北京出版社',
)
new_obj.save() #创建记录,创建一条数据
#批量增加 一次增加多条记录 效率更高
obj_list = []
for i in range(1,10):
obj = models.Book(
title=f'赘婿{i}',
price=45+i*3,
pub_date=f'2020-10-1{i}',
publish='北京出版社',
)
obj_list.append(obj)
models.Book.objects.bulk_create(obj_list) #批量创建
return HttpResponse('ok')
2.简单查询
all() 方法:查询所有记录(查询所有数据的模型类对象),得到的是QuerySet类型数据
obj_list = models.Book.objects.all()
print(obj_list) #QuerySet 类似于列表 里面放的是book模型类对象
# <QuerySet [<Book: 书名: 表净额>, ...]>
# 通过模型类对象获取具体数据
for i in obj_list:
print(i.title) #获取书名
print(i.price) #获取价钱
print(i.publish) #获取出版社
filter() 方法:过滤查询,得到的是QuerySet类型数据
res = models.Book.objects.filter(title='赘婿')
#得到书名为赘婿的QuerySet类型数据 : <QuerySet [<Book: 书名: 赘婿>]>
print(res)
# 获取模型类对象
print(res[0]) # 支持索引切片,不支持负数形式的索引
print(res[0].price) #获取书的价格
get() 方法: 根据已知条件进行过滤查询,但是查询结果有且只能有一条,得到的结果是模型类对象
obj = models.Book.objects.get(title='赘婿')
print(obj) #模型类对象
print(obj.price) #书的价格
3.修改
方式1:update根据Queryset类型数据进行更新,可能批量更新
models.Book.objects.filter(
title='赘婿'
).update( #更新,但是update只能是Queryset类型的数据来进行调用
price = 22,
publish = '好人出版社',
)
方式2:根据模型类对象进行更新,必须执行save()才能保存更新
obj = models.Book.objects.get(id=1) #拿到模型类对象
obj.title = '飞人'
obj.price = 66
obj.save() #保存更新
4.删除
delete() 方法:
#queryset类型的删除,可能是多条数据
models.Book.objects.filter(title='斗破哦').delete()
#模型类对象删除,只能是一条数据
models.Book.objects.get(title='飞人').delete()
在模型类中新增两个字段
auto_now_add和auto_now的问题
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=32)
# title varchar(32) unique
d1 = models.DateField(auto_now_add=True)
d2 = models.DateTimeField(auto_now=True)
def __str__(self):
return '书名为: '+self.title
执行数据库同步指令时,提示:
You are trying to add the field 'd1' with 'auto_now_add=True' to book without a default; the database needs something to populate existing rows.
1) Provide a one-off default now (will be set on all existing rows)
2) Quit, and let me add a default in models.py
解决办法: 字段添加默认是或者设置可以为空
d1 = models.DateField(auto_now_add=True,null=True,blank=True)
d2 = models.DateTimeField(auto_now=True,default=1)
注意:自动添加时间时,django默认是用的utc时间,改为本地时间的设置如下
settings.py文件中改如下配置
TIME_ZONE = 'UTC'
#TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
# USE_TZ = True #使用TIME_ZONE时间
USE_TZ = False # 使用本地时区
auth_now参数如果使用update方法进行数据更新,那么它不会自动更新时间,失效了
想让它生效只能通过save方法更新才会生效,所以,我们一般更新记录时间,都是手动通过datetime模块进行更新