Django_模型类详解(七)

目录

一、定义属性

字段类型

选项

二、查询集

两大特性

查询集的缓存

限制查询集

三、条件查询

条件运算符

1) 查询相等

2) 模糊查询

 3) 空查询

4) 范围查询

5) 比较查询

6) 日期查询

F对象

Q对象

聚合函数

 四、关联查询

通过对象执行关联查询

通过模型类执行关联查询

五、执行原生 SQL 查询

 六、管理器Manager

自定义管理器

自定义管理器类的作用

 模型管理器类与模型类的关系

 七、元选项

源码等资料获取方法


# 定义书籍模型类
class BookInfo(models.Model):btitle = models.CharField(max_length=20)    # 书籍名称bpub_date = models.DateField()              # 发布日期bread = models.IntegerField(default=0)      # 阅读量bcomment = models.IntegerField(default=0)   # 评论量isDelete = models.BooleanField(default=False)   # 逻辑删除# 定义英雄模型类
class HeroInfo(models.Model):hname = models.CharField(max_length=20)     # 英雄姓名hgender = models.BooleanField(default=True)     # 英雄性别,True为男hcomment = models.CharField(max_length=200)     # 英雄描述信息hbook = models.ForeignKey(BookInfo, on_delete=models.DO_NOTHING)       # 英雄与书籍关系为一对多

下面所有例子均使用上面两个模型类

一、定义属性

Django根据属性的类型确定以下信息:

  • 当前选择的数据库支持字段的类型
  • 渲染管理表单时使用的默认html控件
  • 在管理站点最低限度的验证

django会为表创建自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后django不会再创建自动增长的主键列。

默认创建的主键列属性为id,可以使用pk代替,pk全拼为primary key。

注意:pk是主键的别名,若主键名为id2,那么pk是id2的别名。

属性命名限制:

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

字段类型

使用时需要引入django.db.models包,字段类型如下:

  • AutoField:自动增长的IntegerField,通常不用指定,不指定时Django会自动创建属性名为id的自动增长属性。
  • BooleanField:布尔字段,值为True或False。
  • CharField(max_length=字符长度):字符串。
    • 参数max_length表示最大字符个数。
  • TextField:大文本字段,一般超过4000个字符时使用。
  • IntegerField:整数。
  • DecimalField(max_digits=None, decimal_places=None):十进制浮点数。
    • 参数max_digits表示总位数。
    • 参数decimal_places表示小数位数。
  • FloatField:浮点数。
  • DateField[auto_now=False, auto_now_add=False]):日期。
    • 参数auto_now表示每次执行.save保存对象时,自动设置该字段为当前时间(不是数据库默认回填),用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false。
    • 参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false。
    • 参数auto_now_add和auto_now是相互排斥的,组合将会发生错误。
  • TimeField:时间,参数同DateField。
  • DateTimeField:日期时间,参数同DateField。
  • FileField:上传文件字段。

选项

通过选项实现对字段的约束,选项如下:

  • null:如果为True,表示允许为空,默认值是False。
  • blank:如果为True,则该字段允许为空白,默认值是False。
    •   注意:null是数据库范畴的概念,blank是表单验证范畴的。
  • db_column:字段的名称,如果未指定,则使用属性的名称。
  • db_index:若值为True, 则在表中会为此字段创建索引,默认值是False。
  • default:默认值。
  • primary_key:若为True,则该字段会成为模型的主键字段,默认值是False,一般作为AutoField的选项使用。
  • unique:如果为True, 这个字段在表中必须有唯一值,默认值是False。

二、查询集

查询集表示从数据库中获取的对象集合,在管理器上调用某些过滤器方法会返回查询集,查询集可以含有零个、一个或多个过滤器。过滤器基于所给的参数限制查询的结果,从Sql的角度,查询集和select语句等价,过滤器像where和limit子句。

返回查询集的过滤器如下:

  • all():返回所有数据。
  • filter():返回满足条件的数据。
  • exclude():返回满足条件之外的数据,相当于sql语句中where部分的not关键字。
  • order_by():对结果进行排序。

返回单个值的过滤器如下:

  • get():返回单个满足条件的对象
    • 如果未找到会引发"模型类.DoesNotExist"异常。
    • 如果多条被返回,会引发"模型类.MultipleObjectsReturned"异常。
  • count():返回当前查询结果的总条数。
  • aggregate():聚合,返回一个字典。

判断某一个查询集中是否有数据:

  • exists():判断查询集中是否有数据,如果有则返回True,没有则返回False。

两大特性

  • 惰性执行:创建查询集不会访问数据库,直到调用数据时,才会访问数据库,调用数据的情况包括迭代、序列化、与if合用。
  • 缓存:使用同一个查询集,第一次使用时会发生数据库的查询,然后把结果缓存下来,再次使用这个查询集时会使用缓存的数据。

示例:查询所有,编辑booktest/views.py的index视图,运行查看。

# 不会执行查询
books = BookInfo.objects.all()
# 调用时执行查询
for book in books:bid = book.id

查询集的缓存

每个查询集都包含一个缓存来最小化对数据库的访问。

在新建的查询集中,缓存为空,首次对查询集求值时,会发生数据库查询,django会将查询的结果存在查询集的缓存中,并返回请求的结果,接下来对查询集求值将重用缓存中的结果。

限制查询集

可以对查询集进行取下标或切片操作,等同于sql中的limit和offset子句。

注意:不支持负数索引。

对查询集进行切片后返回一个新的查询集,不会立即执行查询。

如果获取一个对象,直接使用[0],等同于[0:1].get(),但是如果没有数据,[0]引发IndexError异常,[0:1].get()如果没有数据引发DoesNotExist异常。

示例:获取第1、2项,运行查看。

list=BookInfo.objects.all()[0:2]

三、条件查询

条件运算符

1) 查询相等

exact:表示判相等。

例:查询编号为1的图书。

list=BookInfo.objects.filter(id__exact=1)  # 字段与运算符使用双下划线连接
可简写为:
list=BookInfo.objects.filter(id=1)

2) 模糊查询

contains:是否包含。

例:查询书名包含'传'的图书。

list = BookInfo.objects.filter(btitle__contains='传')

startswith、endswith:以指定值开头或结尾。

例:查询书名以'部'结尾的图书

list = BookInfo.objects.filter(btitle__endswith='部')

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

 3) 空查询

isnull:是否为null。

例:查询书名不为空的图书。

list = BookInfo.objects.filter(btitle__isnull=False)

4) 范围查询

in:是否包含在范围内。

例:查询编号为1或3或5的图书

list = BookInfo.objects.filter(id__in=[1, 3, 5])

5) 比较查询

 gt、gte、lt、lte:大于、大于等于、小于、小于等于。

 例:查询编号大于3的图书

list = BookInfo.objects.filter(id__gt=3)

不等于的运算符,使用exclude()过滤器。

list = BookInfo.objects.exclude(id=3)

6) 日期查询

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

 例:查询1980年发表的图书。

list = BookInfo.objects.filter(bpub_date__year=1980)

例:查询1980年1月1日后发表的图书。

list = BookInfo.objects.filter(bpub_date__gt=date(1990, 1, 1))

F对象

 之前的查询都是对象的属性与常量值比较,两个属性怎么比较呢? 可使用F对象,被定义在django.db.models中。

语法如下:

F(属性名)

例:查询阅读量大于等于评论量的图书。

from django.db.models import F
...
list = BookInfo.objects.filter(bread__gte=F('bcomment'))

可以在F对象上使用算数运算。

例:查询阅读量大于2倍评论量的图书。

list = BookInfo.objects.filter(bread__gt=F('bcomment') * 2)

Q对象

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

例:查询阅读量大于20,并且编号小于3的图书。

list=BookInfo.objects.filter(bread__gt=20,id__lt=3)
或
list=BookInfo.objects.filter(bread__gt=20).filter(id__lt=3)

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

语法如下:

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

例:查询阅读量大于20的图书,改写为Q对象如下。

from django.db.models import Q
...
list = BookInfo.objects.filter(Q(bread__gt=20))

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

例:查询阅读量大于20,或编号小于3的图书,只能使用Q对象实现

list = BookInfo.objects.filter(Q(bread__gt=20) | Q(pk__lt=3))

Q对象前可以使用~操作符,表示非not。

例:查询编号不等于3的图书。

list = BookInfo.objects.filter(~Q(pk=3))

聚合函数

 使用aggregate()过滤器调用聚合函数。聚合函数包括:Avg,Count,Max,Min,Sum,被定义在django.db.models中。

例:查询图书的总阅读量。

from django.db.models import Sum
...
list = BookInfo.objects.aggregate(Sum('bread'))

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

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

使用count时一般不使用aggregate()过滤器。

例:查询图书总数。

list = BookInfo.objects.count()

注意count函数的返回值是一个数字。

 四、关联查询

关系型数据库的关系包括三种类型:

  • ForeignKey(模型类名称, on_delete=models.DO_NOTHING):创建外键,一对多关系,将字段定义在多的一端中。。

    • on_delete:删除关联表中的数据时,当前表与其关联的field的行为
    • on_delete = models.CASCADE, # 删除主键表中数据时,外键表中与之关联需要先删除

    • on_delete = models.DO_NOTHING, # 删除关联数据,什么也不做

    • on_delete = models.PROTECT, # 删除关联数据,引发错误ProtectedError

    • on_delete = models.SET_NULL, # 删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空,一对一同理)

    • on_delete = models.SET_DEFAULT, # 删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值,一对一同理)

  • ManyToManyField:多对多,将字段定义在任意一端中。
  • OneToOneField:一对一,将字段定义在任意一端中。
  • 可以维护递归的关联关系,使用'self'指定,详见"自关联"。

通过对象执行关联查询

根据主键表查询外键表,语法如下:

主键表实例对象.外键表模型名称_set

例:查询图书id为1的所有英雄信息。

b = BookInfo.objects.get(id=1)
b.heroinfo_set.all()    # 关联的模型类名需要小写

等效于SQL语句:select * from booktest_heroinfo where hbook_id=(select id from booktest_bookinfo where id=1);

根据外键表查询主键表,语法如下:

外键表实例对象.创建外键时的变量名称

例:查询HeroInfo对应的表中id为5的英雄关联的图书

hero = HeroInfo.objects.get(pk=3)    # pk=3指的主键值为3
hero.hbook    #  HeroInfo模型类创建外键的变量是 hbook

等效于SQL语句:select * from booktest_bookinfo where id=(select hbook_id from booktest_heroinfo where id=5);

通过模型类执行关联查询

由多模型类条件查询一模型类数据,语法如下:

关联模型类名小写__属性名__条件运算符=值

例:查询图书,要求图书中英雄的描述包含'六'。

BookInfo.objects.filter(heroinfo__hcontent__contains='六')

等效于SQL语句:select * from booktest_bookinfo where id in (select hbook_id from booktest_heroinfo where hcomment like '%六%');

由一模型类条件查询多模型类数据,语法如下:

一模型类关联属性名__一模型类属性名__条件运算符=值

例:查询书名为“天龙八部”的所有英雄。

HeroInfo.objects.filter(hbook__btitle='天龙八部')

等效于SQL语句:select * from booktest_heroinfo where hbook_id in (select id from booktest_bookinfo where btitle="天龙八部");

五、执行原生 SQL 查询

官方执行原生SQL查询文档的地址:https://docs.djangoproject.com/zh-hans/3.1/topics/db/sql/

使用管理器方法 raw() 能用于执行原生 SQL 查询,语法如下:

 Manager.raw(sql, params=None, translations=None)

该方法接受一个原生 SQL 查询语句,执行它,并返回一个 django.db.models.query.RawQuerySet 实例。这个 RawQuerySet 能像普通的 QuerySet 一样被迭代获取对象实例。

例:查询BookInfo中所有书籍

books = BookInfo.objects.all()
# 等效于上面的代码
books = BookInfo.objects.raw('select * from booktest_bookinfo')

例:查询HeroInfo对应的表中id为7的英雄关联的图书所有信息

hero = HeroInfo.objects.get(pk=3)    # pk=3指的主键值为3
hero.hbook    #  HeroInfo模型类创建外键的变量是 hbook# 等同于
BookInfo.objects.raw('select * from booktest_bookinfo where id=(select hbook_id from booktest_heroinfo where id=7)')
# 等同于
HeroInfo.objects.raw('select * from booktest_bookinfo where id=(select hbook_id from booktest_heroinfo where id=7)')

使用raw()执行需要注意以下方面:

1、使用raw()时,查询出来的是一个 RawQuerySet 对象,能像普通的 QuerySet 一样被迭代获取对象实例。

 2、Django不会对传给 .raw() 的 SQL 语句做任何检查。如果查询的数据不存在会返一个空对象集,而不会像QuerySet 对象有提示

 3、如果需要执行参数化的查询,可以使用 raw() 的 params 参数,防止SQL注入

>>> id = 7
>>> books = HeroInfo.objects.raw('select * from booktest_bookinfo where id=(select hbook_id from booktest_heroinfo where id=%s)', [id])
>>> for book in books:
...     book.btitle
...
'天龙八部'
>>>

不要写成如下样式,有SQL注入的风险

>>> query ='select * from booktest_bookinfo where id=(select hbook_id from booktest_heroinfo where id=%s)' %id
>>>HeroInfo.objects.raw(query)

 六、管理器Manager

前面的查询都是通过   模型类.objects.查询集,比如:BookInfo.objects.all()  那objects是什么东西呢?objects其实是Django帮我们自动生成的一个 models.Manager类的实例对象,也就是管理器,通过这个管理器可以实现对数据的查询。

自定义管理器

 既然objects是一个实例对象,那我们也就能自己定义一个管理器。自定义管理器步骤如下:

  1. 自定义一个管理器类,这个类继承 models.Manager 类
  2. 在模型类中创建自定义的管理器类的实例对象

这个实例对象就是我们自定义的管理器

例:自定义BookInfo模型类的管理器为book,并查看所有书籍

# 自定义模型管理类
class BookInfoManager(models.Manager):pass# 定义书籍模型类
class BookInfo(models.Model):btitle = models.CharField(max_length=20)    # 书籍名称bpub_date = models.DateField()              # 发布日期bread = models.IntegerField(default=0)      # 阅读量bcomment = models.IntegerField(default=0)   # 评论量isDelete = models.BooleanField(default=False)   # 逻辑删除# 自定义模型管理器book = BookInfoManager()def __str__(self):return F"btitle:{self.btitle},bpub_date:{self.bpub_date}"

 从上图中可以看出,一旦我们自定义管理器后,objects这个管理器就会失效。

自定义管理器类的作用

上面自定义的管理器类完全继承了 models.Manager ,没有做任何修改,这样是毫无意义。

自定义管理器类主要用于两种情况:

  1. 修改原始查询集,如重写all()方法
  2. 在管理器类中添加额外的方法,如向数据库中插入数据

1、 修改原始查询集

例如:返回数据库中 isDelete 等于0 的书籍

将上面的  BookInfoManager 修改成如下代码:

class BookInfoManager(models.Manager):# 默认查询未删除的图书信息# 调用父类的成员语法为:super().方法名def all(self):return super().all().filter(isDelete=0)

在shell中调用 all() 方法

 2、在管理器类中添加额外的方法

例如:在管理器类中创建一个添加书籍的 create_book 方法

# 自定义模型管理类
class BookInfoManager(models.Manager):# 默认查询未删除的图书信息# 调用父类的成员语法为:super().方法名def all(self):return super().all().filter(isDelete=0)def create_book(self, title, bpub_date):# 获取 self 所在的模型类。self此时表示实例化对象 objects ,objects所在的模型类就是 BookInfo,所以model_class此时指向的就是 BookInfo。# 使用此方法可以避免因模型类修改名称而导致的实例化找不到类对象的问题model_class = self.model# 创建实例对象book = model_class()# book = BookInfo()book.btitle = titlebook.bpub_date = bpub_datebook.bread = 0book.bcomment = 0book.isDelete = 0book.save()

注:已将上面自定义的管理名从 book 改为 objects,这个objects仍为自定义的管理器

 除了在管理器类中添加额外的方法,我们也能在模型类  BookInfo  中添加类方法来实现相同功能,如:

# 定义书籍模型类
class BookInfo(models.Model):...@classmethoddef cls_create_book(cls, title, bpub_date):# cls 此时代表的是 BookInfo 这个类,book=cls() 也就是 book=BookInfo()book = cls()book.btitle = titlebook.bpub_date = bpub_datebook.bread = 0book.bcomment = 0book.isDelete = 0book.save()

 但是,模型类主要是为了建立与数据库表之间的一种对应关系,假如在模型类中封装过多的方法,就会让模型类中多很多与数据表关联无关的内容,为了将模型类与数据库表之间的关系操作数据库表的方法分离开,所以我们在管理器类中添加操作数据库表的方法。

django已为我们定义了一个创建的通用方法 create ,使用时需要以键值对的方式传入参数:

 模型管理器类与模型类的关系

通过在模型类中创建模型管理器类的实例对象建立联系

 七、元选项

模型类创建的数据表格的格式是:应用名_模型类名,比如BookInfo这个模型类,在数据库中是以booktest_bookinfo作为表名。此时,如果我们修改应用的名称为booktest2,那么模型类对应的表名就变成了 booktest2_bookinfo,但是这个模型类对应的表名已经生成了,此时再去调用这个模型类就会报错。

我们可以通过元选项 Meta 的db_table来指定模型类的表名,一旦指定表名,通过模型类创建的表就不再依赖应用名了。

# 定义书籍模型类
class BookInfo(models.Model):btitle = models.CharField(max_length=20)    # 书籍名称bpub_date = models.DateField()              # 发布日期bread = models.IntegerField(default=0)      # 阅读量bcomment = models.IntegerField(default=0)   # 评论量isDelete = models.BooleanField(default=False)   # 逻辑删除# 自定义模型管理器objects = BookInfoManager()class Meta:db_table = 'bookinfo'

db_table只是django元选项中常用的一个,更多选项请查阅 官方文档:https://docs.djangoproject.com/zh-hans/3.1/ref/models/options/ 


源码等资料获取方法

各位想获取源码的朋友请点赞 + 评论 + 收藏,三连!

三连之后我会在评论区挨个私信发给你们~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/15270.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Squid 缓存代理(一)---原理及搭建(传统代理、透明代理)

前言 Squid 是 Linux 系 统 中 最 常 用 的 一 款 开 源 代 理 服 务 软 件 ( 官 方 网 站 为 http://www.squid-cache.org),可以很好地实现 HTTP 和 FTP,以及 DNS 查询、SSL 等应用的缓存代理。缓存代理作为应用层的代理服务软件…

Python学习笔记-基于socket基础的http服务端程序

通过HTTP协议可以进行通信可以规范化的进行网络间通信。下面技术第一个http服务器小程序。简单的记录第一个试手程序。 1.http通信的基本流程 整个流程对应四层网络架构:应用层、传输层、网络层、链路层。有的部分已经封装,不需要我们再行处理。 2.服务…

SAR ADC version2 ——ADC背景介绍

目录: ADC常用指标分类 静态性能:微分非线性:DNL 积分非线性:INL 仿真测试DNL:(码密度法)(code density&…

1.Git使用技巧-常用命令1

Git使用技巧-常用命令 文章目录 Git使用技巧-常用命令一、git 创建仓库demo 二、本地仓库常用命令提交详解git commitgit commit --amend 三、 推送到远程分支git push 总结参考 一、git 创建仓库 创建远端仓库: git init – bare // 创建远端裸仓库; 远…

哈工大计算网络课程数据链路层详解之:数据链路层服务

哈工大计算网络课程数据链路层详解之:数据链路层服务 在介绍完网络层的实现功能和协议之后,接下来我们继续介绍网络层的下一层:数据链路层。 本节首先对数据链路层的功能和所提供的服务进行概述。 如下图示例网络所示,标红色的部…

18.Lucas-Kanade光流及OpenCV中的calcOpticalFlowPyrLK

文章目录 光流法介绍OpenCV中calcOpticalFlowPyrLK函数补充reference 欢迎访问个人网络日志🌹🌹知行空间🌹🌹 光流法介绍 光流描述了像素在图像中的运动,就像彗星☄划过天空中流动图像。同一个像素,随着时…

【三】部署zabbix-proxy代理服务器和高可用,以及监控windows系统和java应用

zabbix代理服务器和高可用 1.部署zabbix代理服务器1.1 代理端zabbix-proxy配置1.2 客户端zabbix-agent配置1.3 zabbix-proxy总结 2. 部署Zabbix高可用集群2.1 主节点zabbix-server配置2.2 备节点zabbix-server配置2.3 客户端zabbix_agent配置2.4 Zabbix高可用集群总结 3.Zabbix…

【uniapp开发小程序】实现读取手机剪切板第一条,识别并以姓名/手机号/收货地址格式输出

效果图&#xff1a; 完整代码&#xff1a; <template><view class""><text>测试</text><view click"pasteContent()" class"content">点击此处可快速识别 您的收货信息</view></view> </templat…

WAIC2023记录

汤晓鸥 学生与工作&#xff1a; 微软布局大模型方向

Linux高频常用指令汇总

目录 认识 Linux 目录结构 绝对路径&#xff1a;以根目录开头的, 称为绝对路径 相对路径&#xff1a;不是根目录开头的,称为相对路径 ls pwd cd mkdir touch cat echo rm cp mv vim编辑器 1、进入文件 2、进行编辑模式 3、保存退出 重要的几个热键[Tab],[ct…

如何利用Spine制作简单的2D骨骼动画

在2D游戏中&#xff0c;我们经常看到各种各样的角色动画。动画能给游戏带来生机和灵气。创作一段美妙的动画&#xff0c;不仅需要强大的软件工具&#xff0c;更需要一套完善的工作流程。 Spine就是一款针对游戏开发的2D骨骼动画编辑工具。Spine 可以提供更高效和简洁 的工作流…

【电子学会】2023年05月图形化四级 -- 还原轨迹

还原轨迹 1. 准备工作 &#xff08;1&#xff09;删除小猫&#xff1b; &#xff08;2&#xff09;从角色库添加“Butterfly 1”角色&#xff1b; &#xff08;3&#xff09;保留白色背景。 2. 功能实现 &#xff08;1&#xff09;点击绿旗&#xff0c;清除舞台&#xff…