django -- ORM查询

前戏

在咱们以前操做ORM中,你也许是启动Django项目,经过地址访问固定的函数,或者在pycharm里的python console里执行,第一种比较麻烦,并且每次都要启动项目,写路由,第二种虽然不须要写路由,可是写的东西保存不下来,只要关闭就没有了。今天来经过python脚本的形式来写,既不须要启动项目,也能够保存java

在项目下面建立一个python文件,里面写以下代码python

import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "项目名.settings") import django django.setup() from appTest01 import models  # 导入视图函数
    obj = models.Person.objects.all() print(obj)

这样咱们就能够写ORM语句,只须要右键运行就能够了linux

若是想查看ORM转为的SQL语句,只须要在项目的settings.py里写以下代码就能够把SQL语句打印到控制台上sql

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

ORM经常使用查询

数据库里数据以下数据库

import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_project.settings") import django django.setup() from appTest01 import models # all() 查询全部结果,返回的是对象列表。若是要获取对应的字段值,先取索引,在用.字段名
    # 好比下面的要获取第二个姓名,ret[1].name
    ret = models.Person.objects.all() # print(ret) <QuerySet [<Person: Person object>, <Person: Person object>, <Person: Person object>]>

    # get() 查询到的是对象,有且只能有一个,要否则会报错,要获取对应的字段值直接用.
    # 好比下面的要获取姓名,ret.name
    ret = models.Person.objects.get(id=1) # print(ret) Person object

    # filter() 查询出知足条件的对象,返回的是对象列表,获取对应的值也要使用索引的方式
    ret = models.Person.objects.filter(id=1) # print(ret) <QuerySet [<Person: Person object>]>

    # exclude() 查询出全部不知足条件的对象,返回的是对象列表,获取对应的值也要使用索引的方式
    ret = models.Person.objects.exclude(id=1)[1] # print(ret.name) 王五

    # value() 具体的数据,没有指定参数,获取全部的字段数据,指定参数,获取指定字段数据
    ret = models.Person.objects.values() # for i in ret:
    # print(i)
    ''' {'id': 1, 'name': 'zouzou', 'age': 25, 'birth': datetime.datetime(2019, 7, 19, 15, 7, 15, 296496, tzinfo=<UTC>)} {'id': 2, 'name': '张三', 'age': 43, 'birth': datetime.datetime(2019, 7, 20, 14, 4, 4, tzinfo=<UTC>)} {'id': 3, 'name': '王五', 'age': 23, 'birth': datetime.datetime(2019, 7, 28, 14, 4, 23, tzinfo=<UTC>)} '''

    # values_list() 具体的数据,没有指定参数,获取全部的字段数据,指定参数,获取指定字段数据
    ret = models.Person.objects.values_list() # for i in ret:
    # print(i)
    ''' (1, 'zouzou', 25, datetime.datetime(2019, 7, 19, 15, 7, 15, 296496, tzinfo=<UTC>)) (2, '张三', 43, datetime.datetime(2019, 7, 20, 14, 4, 4, tzinfo=<UTC>)) (3, '王五', 23, datetime.datetime(2019, 7, 28, 14, 4, 23, tzinfo=<UTC>)) '''

    # order_by() 对查询结果排序,前面加-表示降序,不写表示升序
    # 能够指定多个字段,若是第一个字段相同,则以第二个排,以此类推
    ret = models.Person.objects.all().order_by('-id')[0] # print(ret.id) 3

    # reverse() 对查询结果反向排序,请注意reverse()一般只能在具备已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)
    # ordering=('id',)
    ret = models.Person.objects.all().order_by('-id').reverse()[0] # print(ret.id) 1

    # distinct() 去重 从返回结果中剔除重复纪录(若是你查询跨越多个表,可能在计算QuerySet时获得重复的结果。此时可使用distinct(),注意只有在PostgreSQL中支持按字段去重。)

    # count() 计数
    ret = models.Person.objects.all().count() # print(ret) 3

    # first() 返回第一条记录,取值不须要按索引
    ret = models.Person.objects.all().first() # print(ret.name) zouzou

    # last() 返回最后一条记录,取值不须要按索引
    ret = models.Person.objects.all().last() # print(ret.name) 王五

    # exists() 若是QuerySet包含数据,就返回True,不然返回False
    ret = models.Person.objects.filter(name='赵六').exists() # print(ret) False

总结:django

返回QuerySet对象的方法有并发

all()app

filter()ide

exclude()函数

order_by()

reverse()

distinct()

特殊的QuerySet

 values()         返回一个可迭代的字典序列

values_list()    返回一个可迭代的元组序列

返回具体对象的

get()

first()

last()

返回布尔值的

exists()

返回数字的

count()

双下划线方法

前面的都是查询某个值等于什么什么的。可是咱们常常会查询大于多少,好比成绩大于60分的,这时候就要用到双下滑线方法了

ret = models.Person.objects.filter(id__gt=1)  # id大于1
 ret = models.Person.objects.filter(id__gte=1)  # id大于等于1
 ret = models.Person.objects.filter(id__lt=3)  # id小于3
 ret = models.Person.objects.filter(id__lte=3)  # id小于等于3

 ret = models.Person.objects.filter(id__in=[1, 3])  # id为1和3的
 ret = models.Person.objects.filter(id__gte=1, id__lte=3)  # id大于等于1而且小于等于3的
ret = models.Person.objects.filter(id__range=[1,3])  # id大于等于1而且小于等于3的
 ret = models.Person.objects.filter(name__contains='u')  # name里包含字母u的,区分大小写
ret = models.Person.objects.filter(name__icontains='u')  # name里包含字母u的,不区分大小写
 ret = models.Person.objects.filter(name__startswith='z')  # 以z开头,区分大小写
ret = models.Person.objects.filter(name__istartswith='z')  # 以z开头,不区分大小写
ret = models.Person.objects.filter(name__endswith='u')  # 以u结尾,区分大小写
ret = models.Person.objects.filter(name__iendswith='u')  # 以u结尾,不区分大小写
 ret = models.Person.objects.filter(birth__year='2019')  # 查询年份为2019

 ForeignKey查询

先来建立几张表

class Press(models.Model): name = models.CharField(max_length=32) def __str__(self): return '<Press %s-%s>'%(self.id,self.name) class Book(models.Model): title = models.CharField(max_length=32) price = models.IntegerField() publisher = models.ForeignKey(to='Press') def __str__(self): return '<Book %s-%s>'%(self.id, self.title) class Author(models.Model): name = models.CharField(max_length=32) books = models.ManyToManyField(to='Book')
建立表

往press表和book表里添加一些数据,以下

book_obj = models.Book.objects.get(id=1) print(book_obj.title)  # linux
print(book_obj.price)  # 22
print(book_obj.publisher_id)  # 2
print(book_obj.publisher)  # publisher对应的上Press表,因此是press对象---》<Press 2-清华出版社>
print(book_obj.publisher.name)  # press里对应的name---》清华出版社

查找上海出版社的书

常规写法

models.Book.objects.filter(publisher_id=models.Press.objects.get(name='上海出版社').id)

结果:

<QuerySet [<Book: <Book 2-python入门到放弃>>, <Book: <Book 3-java直接放弃>>]>

高级写法

obj = models.Book.objects.filter(publisher__name='上海出版社')

publisher__name ,前面的publisher为Book表里的字段,对应的结果是Press这个表对象,__name表示press表里的name字段

反向查询

上面的查询是经过book表查询press表的里数据,由于外键是写在book表里的,咱们把这种叫作正向查询

经过press表查询book表里的数据,咱们叫作反向查询

经过press里的id查找对应的书

obj = models.Press.objects.get(id=3) print(obj.book_set.all())

结果:

<QuerySet [<Book: <Book 2-python入门到放弃>>, <Book: <Book 3-java直接放弃>>]>

book_set,表名小写_set获得的是一个管理对象,若是要获取全部的对象,在后面写.all()

还有另外一种写法是在表里的字段后面写上related_name

class Book(models.Model): title = models.CharField(max_length=32) price = models.IntegerField() publisher = models.ForeignKey(to='Press', related_name='mybook') def __str__(self): return '<Book %s-%s>'%(self.id, self.title)

上面的查询就变成

obj = models.Press.objects.get(id=3) print(obj.mybook.all())

正向查询书名也要用mybook_xxx='xxx' 

根据书名查询出版社

常规写法

obj = models.Press.objects.filter(id=models.Book.objects.get(title='python入门到放弃').publisher_id)

结果:

<QuerySet [<Press: <Press 3-上海出版社>>]>

高级写法

obj = models.Press.objects.filter(book__title='python入门到放弃')

 ManyToManyField

在咱们建立表的时候,book和author是多对多的关系,先来看一下他们之间的关系

 

 set()  更新model对象的关联对象

obj = models.Author.objects.get(id=1) # print(obj.name) 孙悟空
 obj.books.set(models.Book.objects.all())

obj = models.Author.objects.get(id=1) # print(obj.name) 孙悟空
 obj.books.set([1,3])

 add() 把指定的model对象添加到关联对象集中。

obj = models.Author.objects.get(id=1) # print(obj.name) 孙悟空
 obj.books.add(*[2,4])

add还能够这样写

obj.books.add(1,2,3,4) obj.books.add(*models.Book.objects.all())

remove() 从关系对象中移除执行的model对象

obj = models.Author.objects.get(id=1) # print(obj.name) 孙悟空

obj.books.remove(1,4)

删除所有

obj = models.Author.objects.get(id=1) # print(obj.name) 孙悟空
 obj.books.remove(*models.Book.objects.all())

clear()  从关联对象集中移除一切对象

obj = models.Author.objects.get(id=1) # print(obj.name) 孙悟空
 obj.books.clear()

建立书和对应的关系

obj = models.Author.objects.get(id=1) # print(obj.name) 孙悟空
 obj.books.create(title='一小时精通Django',price=66,publisher_id=3)

 

反向查询

class Author(models.Model): name = models.CharField(max_length=32) books = models.ManyToManyField(to='Book')

由于books是写在Author表里,因此经过Author查询book表里的是正向查询,经过book表查询author表里的是反向查询

obj = models.Book.objects.get(id=5) print(obj.author_set.all())

反向查询要使用表名_set

注意:对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。

栗子

ForeignKey字段没设置null=True时

class Book(models.Model): title = models.CharField(max_length=32) publisher = models.ForeignKey(to=Publisher)

没有clear()和remove()方法:

>>> models.Publisher.objects.first().book_set.clear() Traceback (most recent call last): File "<input>", line 1, in <module> AttributeError: 'RelatedManager' object has no attribute 'clear'

当ForeignKey字段设置null=True时

class Book(models.Model): name = models.CharField(max_length=32) publisher = models.ForeignKey(to=Class, null=True)

此时就有clear()和remove()方法:

models.Publisher.objects.first().book_set.clear()

聚合查询

在sql语句中,咱们知道聚合语句,好比查询最大值,最小值,平均值等等。在ORM中,使用aggregate()来进行聚合查询,首先须要导入

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

查询价格最大是多少

from django.db.models import Max, Min, Avg, Sum, Count ret = models.Book.objects.aggregate(Max('price')) print(ret) ret = models.Book.objects.all().aggregate(Max('price')) print(ret)

结果:

{'price__max': 66} {'price__max': 66}

结果是一个字典格式,key为“字段_聚合名”,若是你看它不爽,你也能够自定义

from django.db.models import Max, Min, Avg, Sum, Count ret = models.Book.objects.aggregate(最大值=Max('price'),最小值=Min('price')) print(ret)

结果:

{'最大值': 66, '最小值': 22}

注意:若是你查询了多个,有些聚合你本身定义了名称,有些你没有定义名称,则没有定义名称的要放在前面(位置参数不能在关键字参数后面)

分组查询

先来看一下数据表关系

查询出每本书的做者

from django.db.models import Max, Min, Avg, Sum, Count ret = models.Book.objects.annotate(num=Count('author')) print(ret)

结果是QuerySet

<QuerySet [<Book: Book object>, <Book: Book object>, <Book: Book object>, <Book: Book object>, <Book: Book object>]>

使用.values()获取全部

from django.db.models import Max, Min, Avg, Sum, Count ret = models.Book.objects.annotate(num=Count('author')).values() for i in ret: print(i)

结果:

{'id': 1, 'title': 'linux', 'price': 22, 'publisher_id': 2, 'num': 1} {'id': 2, 'title': 'python入门到放弃', 'price': 55, 'publisher_id': 3, 'num': 0} {'id': 3, 'title': 'java直接放弃', 'price': 22, 'publisher_id': 3, 'num': 1} {'id': 4, 'title': 'go精通', 'price': 54, 'publisher_id': 1, 'num': 2} {'id': 5, 'title': '一小时精通Django', 'price': 66, 'publisher_id': 3, 'num': 1}

能够在value里指定参数获取想要的字段

from django.db.models import Max, Min, Avg, Sum, Count ret = models.Book.objects.annotate(num=Count('author')).values('title','num') for i in ret: print(i)

结果:

num对应的值就是这本书做者的个数

{'title': 'linux', 'num': 1} {'title': 'python入门到放弃', 'num': 0} {'title': 'java直接放弃', 'num': 1} {'title': 'go精通', 'num': 2} {'title': '一小时精通Django', 'num': 1}

统计每一个出版社最便宜的书的价格

from django.db.models import Max, Min, Avg, Sum, Count ret = models.Book.objects.values('publisher_id').annotate(min_num=Min('price')) for i in ret: print(i)

结果:

{'publisher_id': 1, 'min_num': 54} {'publisher_id': 2, 'min_num': 22} {'publisher_id': 3, 'min_num': 22}

由于不分组的结果

from django.db.models import Max, Min, Avg, Sum, Count ret = models.Book.objects.values('publisher_id') for i in ret: print(i)

结果:

{'publisher_id': 1} {'publisher_id': 2} {'publisher_id': 3} {'publisher_id': 3} {'publisher_id': 3}

统计不止一个做者的图书

ret = models.Book.objects.annotate(num=Count('author')).filter(num__gt=1).values() for i in ret: print(i)

结果:

{'id': 4, 'title': 'go精通', 'price': 54, 'publisher_id': 1, 'num': 2}

查询各个做者出的书的总价格

F查询

在以前的查询中,咱们都是拿某个字段对一个固定的值作比较,若是想用字段和字段作比较,就要用到F查询了,先来看下数据表里的数据

需求,查出全部num大于money的

from django.db.models import F ret = models.Book.objects.filter(num__gt=F('money')).values() for i in ret: print(i)

结果:

{'id': 1, 'title': 'linux', 'price': 22, 'publisher_id': 2, 'money': 23, 'num': 65} {'id': 4, 'title': 'go精通', 'price': 54, 'publisher_id': 1, 'money': 33, 'num': 88} {'id': 5, 'title': '一小时精通Django', 'price': 66, 'publisher_id': 3, 'money': 44, 'num': 99}

需求:给每一个num的值*2

以前的都是对某一条数据更新的,如

ret = models.Book.objects.get(id=2) ret.num=24 ret.save()

上面的这种写法要进行save(),并且要写更新的具体数值

使用update更新

ret = models.Book.objects.filter(id=2).update(num=50)

update就不须要save

ret = models.Book.objects.update(num=50)  # 对全部的数据更新

这两种写法都知足不了咱们的需求,咱们用F来实现,下面两种结果是同样的

from django.db.models import F ret = models.Book.objects.update(num=F('num')*2) ret = models.Book.objects.all().update(num=F('num')*2)

需求:在全部书名后面加上(测试)

ret = models.Book.objects.update(title=Concat(F("title"), Value("("), Value("测试"), Value(")")))

不须要()

ret = models.Book.objects.update(title=Concat(F("title"), Value("测试")))

Q查询

以前咱们全部进行的查询都是and关系的,若是要使用or关系的查询,就要用Q查询了。继续看数据表数据

需求:查询id小于3而且大于等于6的

from django.db.models import Q ret = models.Author.objects.filter(Q(id__lt=3) | Q(id__gte=6)).values() for i in ret: print(i)

结果:管道符( | )表示或的关系

{'id': 1, 'name': '孙悟空'} {'id': 2, 'name': '猪八戒'} {'id': 6, 'name': '蜘蛛精'} {'id': 7, 'name': '女儿国'} {'id': 8, 'name': '紫霞仙子'}

&表示而且的关系

from django.db.models import Q ret = models.Author.objects.filter(Q(id__lt=7) & Q(id__gte=6)).values() for i in ret: print(i)

结果:

{'id': 6, 'name': '蜘蛛精'}

~表示取反

from django.db.models import Q ret = models.Author.objects.filter(~Q(id__lt=7) & Q(id__gte=6)).values() for i in ret: print(i)

结果:

{'id': 7, 'name': '女儿国'} {'id': 8, 'name': '紫霞仙子'}

事务

事务(Transaction)是并发控制的基本单位。所谓的事务,它是一个操做序列,这些操做要么都执行,要么都不执行,它是一个不可分割的工做单位。例如,银行转帐工做:从一个帐号扣款并使另外一个帐号增款,这两个操做要么都执行,要么都不执行。因此,应该把它们当作一个事务。事务是数据库维护数据一致性的单位,在每一个事务结束时,都能保持数据一致性。
针对上面的描述能够看出,事务的提出主要是为了解决并发状况下保持数据一致性的问题。
事务具备如下4个基本特征。

  • Atomic(原子性):事务中包含的操做被看作一个逻辑单元,这个逻辑单元中的操做要么所有成功,要么所有失败。
  • Consistency(一致性):只有合法的数据能够被写入数据库,不然事务应该将其回滚到最初状态。
  • Isolation(隔离性):事务容许多个用户对同一个数据进行并发访问,而不破坏数据的正确性和完整性。同时,并行事务的修改必须与其余并行事务的修改相互独立。
  • Durability(持久性):事务结束后,事务处理的结果必须可以获得固化。
import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_project.settings") import django django.setup() from appTest01 import models try: from django.db import transaction with transaction.atomic(): 这里写要执行的ORM语句 except Exception as e: print(str(e))
相关文章
相关标签/搜索