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模块进行更新

原文地址:https://www.cnblogs.com/jia-shu/p/14589776.html