Django之ORM表间操作

 

之前完成了简单的数据库数据增加操作。这次学习更多的表间操作。

单表操作

增加

方式一

    b = Book(title="Python基础",  publication_date="2019-10-15", price=20)
b.save()

这是我们之前增加数据的方式,是用实例化对象的方式来添加数据的,这是添加数据的一种方式,接下来,我们看看其他的添加数据的方式。

方式二

    Book.objects.create(title="Python基础",  publication_date="2019-10-15", price=20)

这种方式来添加数据,不需要创建变量来接收和使用save()保存就会直接将数据添加到数据库。

删除

方式一

    b = Book.objects.get(title="Python基础")
b.delete()

方式二

    Book.objects.filter(title="Python基础").delete()

修改

方式一

    book = Book.objects.get(name="天龙八部")
book.name = "天龙八部2"
book.save()

方式二

    Book.objects.filter(name="天龙八部2").update(name="天龙八部")  # 注意不能用get取值

这里注意,使用get取到的是一个对象,而使用filter获取的是一个查询集。

补充内容

如果你想看你的每个操作对应的是什么sql语句的话,需要在setting加上日志记录部分

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

查看对应sql语句之后,我们可以查看对应的sql语句。如果查看两种修改数据的方式,会发现save()函数的执行效率是很低的。

注:在插入和更新数据中,save()方法是更新一行里面的所有列,而某些情况下,我们只需要更新行里的某几列,这个方法会把每个列都重新赋值,不论是不是修改过的,所以这个的效率是特别低的,如果在像修改这样的操作(update),是修改你改的那个字段,其他的并不会重新赋值。

#---------------- update方法直接设定对应属性----------------
models.Book.objects.filter(id=3).update(title="PHP")
##sql:
##UPDATE "app01_book" SET "title" = 'PHP' WHERE "app01_book"."id" = 3; args=('PHP', 3) #--------------- save方法会将所有属性重新设定一遍,效率低-----------
obj=models.Book.objects.filter(id=3)[0]
obj.title="Python"
obj.save()
# SELECT "app01_book"."id", "app01_book"."title", "app01_book"."price",
# "app01_book"."color", "app01_book"."page_num",
# "app01_book"."publisher_id" FROM "app01_book" WHERE "app01_book"."id" = 3 LIMIT 1;
#
# UPDATE "app01_book" SET "title" = 'Python', "price" = 3333, "color" = 'red', "page_num" = 556,
# "publisher_id" = 1 WHERE "app01_book"."id" = 3;

查询

相关记录查询

查询相关API,使用方法:

模型类名.objects.查询内容
# 查询相关API:

#  <1>filter(**kwargs):      它包含了与所给筛选条件相匹配的对象

#  <2>all():                 查询所有结果

#  <3>get(**kwargs):         返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。

#-----------下面的方法都是对查询的结果再进行处理:比如 objects.filter.values()--------

#  <4>values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列

#  <5>exclude(**kwargs):     它包含了与所给筛选条件不匹配的对象

#  <6>order_by(*field):      对查询结果排序

#  <7>reverse():             对查询结果反向排序

#  <8>distinct():            从返回结果中剔除重复纪录

#  <9>values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列

#  <10>count():              返回数据库中匹配查询(QuerySet)的对象数量。

# <11>first():               返回第一条记录

# <12>last():                返回最后一条记录

#  <13>exists():             如果QuerySet包含数据,就返回True,否则返回False。

我们可以给模型类中加入"__str__"魔法方法,这样当我们打印一个对象的时候,就会输出这个魔法方法中对应的内容。

def __str__(self):
return self.name

这样修改之后,方便我们用控制台查看相关内容。

记录中指定字段的查询

    book_list = Book.objects.all().values("title", "price")

如果使用values(),结果会以字典形式存储,如果使用values_list(),会以元组方式进行存储。这里如果进行修改,就需要修改前端的调用方式,因为如果是字典形式数据,是使用键来进行内容读取,而元组和列表是使用下标进行内容读取。

模糊查询

目前,我们已经可以完成基本的数据查询,比如相关记录查询和指定字段查询。但是在大部分的实际使用中,我们要对字段信息进行筛选,比如,查询价格大于50的相关记录。

当我们在筛选条件中加入相关判断的时候,会出现报错,说明这种写法并不正确。这里就需要用到神奇的双下划线的相关用法。

    book_list = Book.objects.filter(price__gt = 20).values("title", "price")
# 1)模糊查询
contains:是否包含。
startswith、endswith:以指定值开头或结尾。
# 2) 空查询
isnull:是否为null。
# 3) 范围查询
in:是否包含在范围内。
# 4) 比较查询
gt、gte、lt、lte:大于、大于等于、小于、小于等于。
# 5) 日期查询
year、month、day、week_day、hour、minute、second:对日期时间类型的属性进行运算。
Model.objects.all()       # 获取所有对象的QuerySet
Model.objects.filter() # 获取满足条件的对象的QuerySet
Model.objects.exclude() # 获取不满足条件的对象的QuerySet
Model.objects.get() # 获取单个符合条件的对象的QuerySet Person.objects.all().extra(select={'is_adult': "age > 18"}) querySet.distinct() 去重复
__exact 精确等于 like 'aaa'
__iexact 精确等于 忽略大小写 ilike 'aaa'
__contains 包含 like '%aaa%'
__icontains 包含 忽略大小写 ilike '%aaa%',但是对于sqlite来说,contains的作用效果等同于icontains。
__gt 大于
__gte 大于等于
__lt 小于
__lte 小于等于
__in 存在于一个list范围内
__startswith 以...开头
__istartswith 以...开头 忽略大小写
__endswith 以...结尾
__iendswith 以...结尾,忽略大小写
__range 在...范围内
__year 日期字段的年份
__month 日期字段的月份
__day 日期字段的日
__isnull=True/False

一对多表间关系操作

一对多之增加记录

方式一

出版社表相关信息已有,然后创建book表记录

    Book.objects.create(title="西游记", publisher_id=1, publication_date="2018-11-1", price=99)

这种方式,我们直接使用publisher_id来进行赋值。

方式二

这种赋值方式是对publisher进行赋值操作

pub_obj = Publisher.objects.get(name="南方出版社")
Book.objects.create(title="水浒传", publisher=pub_obj, publication_date="2018-11-1", price=99)

一对多查询之对象查询

之前,我们可以通过查询来获取一个对象,也就是表中的相关记录,然后通过调用类属性的方式来得到记录中的相关字段。

    book_obj = Book.objects.get(title="悲惨世界")
print(book_obj.title)
print(book_obj.publication_date)
print(book_obj.price)

上面的操作方式仅限于单表,而表与表之间一般会存在着很多的关系,那么在一对多的表间关系中,如何去查询我们想要的内容呢?

现在我们将之前注释掉的设置书籍与出版社一对多关系的设置解开。

因为此时我们修改了表的相关字段,所以需要重新迁移和生成相关数据表,再手动加入一些记录。

接下来,修改views相关内容,查看相关字段。

我们建立模型类的时候是使用publisher作为字段名的,所以这里打印这个字段看看对应内容。

可以看到,打印这个外键得到的时一个publisher对象。其实这个对象就是这个书籍对应的出版社记录。而这个时候,我们可以用"."来获取里面的相关信息。

    print(book_obj.publisher.name)
print(book_obj.publisher.city)

总结:

一对多的表间关系中,获得“多”表中记录时,拿到的外键值一定是一个对象。

多对多表间关系操作

多对多的表间关系其实是创建了一个第三方表来存放着他们的关系。我们将之前Book类中注释的多对多关系解开然后重写迁移和生成相关数据表。然后手动往作者表和图书表与作者表的多对多关系表中添加基本信息。

现在book表和author表都有了相关的数据,接下来要往这个多对多的表中添加关联的数据。现在有一个问题,通过查看数据库,我们可以看到这个多对多关联的表,但是我们并没有在模型类中定义这个表,也就是说没有办法通过”模型类名.objects.create()”等方法来创建记录。所以我们只能通过对象方式来绑定关系。

这个是我们模型类中定义的表间关系,之前我们可以通过"Book对象.publisher"来获取这个图书对应的publisher对象。那么"Book对象.author"应该是这本书绑定关系的作者信息。

    b = Book.objects.get(id=3)
print(b.authors.all())

当打印之后为两个作者对象。

为了方便查看,可以在Author对象中定义“__str__"魔法函数。

    def __str__(self):
return self.title

上面的查找方式是正向查找,除了正向查找,还可以用在一对多查找中使用的"模型类名_set”来进行反向查找。

    b = Author.objects.get(id=2)
print(b.book_set.all())

前面,我们简单介绍了多对多表内容间的查询,接下来,我们看看如何用对象的方式来往表中添加数据。

    b = Book.objects.get(id=3)
a = Author.objects.get(id=1)
b.authors.add(a)

上面这种是添加一条对应关系,如果给一本书添加多个作者,用以下方式:

    b = Book.objects.get(id=3)
a = Author.objects.all()
b.authors.add(*a)

添加使用的是add()函数,想要解除,可以使用remove()函数,它的使用方式和add函数一致。

注意:除了这种方式,我们还可以在model中自己创建一个多对多的表,然后对其进行操作。

class Book_Author(models.Model):
book = models.ForeignKey("Book")
author = models.ForeignKey("Author")

Django 的ORM 表间操作的更多相关文章

  1. Django的ORM常用查询操作总结(Django编程-3)

    Django的ORM常用查询操作总结(Django编程-3) 示例:一个Student model: class Student(models.Model): name=models.CharFiel ...

  2. Django之ORM表操作

    ORM表操作 1.ORM单表操作 首先想操作表的增删改查,需要先导入这个表,以之前创建的UserInfo表为例,在app下的views.py中导入 from app import models def ...

  3. Django之mysql表单操作

    在Django之ORM模型中总结过django下mysql表的创建操作,接下来总结mysql表记录操作,包括表记录的增.删.改.查. 1. 添加表记录 class UserInfo(models.Mo ...

  4. Django之form表单操作

    小白必会三板斧 from django.shortcuts import render,HttpResponse,redirect HttpRespone:返回字符串 render:返回html页面 ...

  5. Django中ORM表的创建以及基本增删改查

    Django作为重量级的Python web框架,在做项目时肯定少不了与数据库打交道,编程人员对数据库的语法简单的还行,但过多的数据库语句不是编程人员的重点对象.因此用ORM来操作数据库相当快捷.今天 ...

  6. Django的ORM那些相关操作

    一般操作 看专业的官网文档,做专业的程序员! 必知必会13条 <> all(): 查询所有结果 <> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象 & ...

  7. Django之Orm的各种操作

    1.一般操作 ***必知必会13条*** <1> all(): 查询所有结果 <2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象 models.Cu ...

  8. Django之ORM那些相关操作

    一般操作 看专业的官网文档,做专业的程序员! 必知必会13条 <1> all(): 查询所有结果 <2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象 ...

  9. Django之ORM其他骚操作

    Django ORM执行原生SQL # extra # 在QuerySet的基础上继续执行子语句 # extra(self, select=None, where=None, params=None, ...

随机推荐

  1. 对cookie-parser的理解(签名、加密)

    1.为什么说要利用签名防止cookie被恶意篡改 我们在浏览器输入用户名和密码发送post请求到后端服务器,后端服务器验证合法,返回响应,并Set-Cookie为sessionid=***;usern ...

  2. SAP OB52会计年度变式

    Var.(Posting Period Variant) 记帐区间变式,每个公司代码对应一个记帐期间变式,多个公司代码可以使用一个相同的记帐期间变式 A(Performance Assistant) ...

  3. SAP MM 供应商无英文名称,ME21N里却带出了英文名字?

    SAP MM 供应商无英文名称,ME21N里却带出了英文名字? 近日收到客户业务用户上报的一个问题说ME21N的时候,供应商101071的名字怎么是英文名字,实际上供应商主数据里是没有这个英文名字, ...

  4. 微信小程序根据生日获取年龄

    // 根据出生日期计算年龄周岁 传参格式为1996-06-08 // 根据出生日期计算年龄周岁 传参格式为1996-06-08 function getAge(strBirthday) { var r ...

  5. ubuntu 18.04下安装JDK

    一.安装前检查 检查是否已经安装 java -version 二.安装方式 1)通过ppa(源) 2)通过官网安装包安装  JDK官网下载地址  或百度云下载地址,提取码 rzq5 三.安装步骤 (一 ...

  6. Linux下基于shell脚本实现学生信息管理系统

    #该管理系统是参考两位博主(时间有点远了,我忘了,请博主看到后联系我)后自行修改添加的.登录过程还有很多不完善,我就抛砖引玉啦. 废话不多,直接上码! #!/bin/bash# 学生管理系统# @ve ...

  7. JUC-0-JUC简介

    Java JUC  简介   在 Java 5.0 提供了 java.util.concurrent (简称 JUC )包,在此包中增加了在并发编程中很常用 的实用工具类,用于定义类似于线程的自定义子 ...

  8. Cent OS6.5——网络配置

    1.已安装centos 系统,打开虚拟机,并开机进入centos系统 2.进行网络配置,必须先确认以下几个点: 2-1.网络适配器模式是否为NAT模式,点击虚拟机,选择设置 ——选择网络适配器,NAT ...

  9. phoenix中添加二级索引

    Phoenix创建Hbase二级索引 官方文档 1. 配置Hbase支持Phoenix创建二级索引   1.  添加如下配置到Hbase的Hregionserver节点的hbase-site.xml  ...

  10. P3525 INS-Inspection

    这道题的题面有点问题,如果按照题面做,应该是A不了的,下面引用一下评论里@REM_001的翻译 一棵n个节点的树,行动中心S从1->N.从S出发前往任意一个未标记到的点(沿树上两点的唯一路径走) ...