django -- ORM查询(一)

简介: django -- ORM查询

前戏


在我们之前操作ORM中,你也许是启动Django项目,通过地址访问固定的函数,或者在pycharm里的python console里执行,第一种比较麻烦,而且每次都要启动项目,写路由,第二种虽然不需要写路由,但是写的东西保存不下来,只要关闭就没有了。今天来通过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语句,只需要右键运行就可以了

如果想查看ORM转为的SQL语句,只需要在项目的settings.py里写如下代码就可以把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

总结:

返回QuerySet对象的方法有

all()

filter()

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查询


先来创建几张表

创建表

往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()

相关文章
|
7月前
|
存储 关系型数据库 数据库
Django创建应用、ORM的进阶使用及模型类数据库迁移1
Django创建应用、ORM的进阶使用及模型类数据库迁移1
74 0
|
6月前
|
SQL 关系型数据库 MySQL
Django入门ORM(Django操作MySQL) 专题一
Django入门ORM(Django操作MySQL) 专题一
|
7月前
|
存储 数据可视化 数据库
Django创建应用、ORM的进阶使用及模型类数据库迁移3
Django创建应用、ORM的进阶使用及模型类数据库迁移3
52 0
|
7月前
|
关系型数据库 MySQL 数据库
Django创建应用、ORM的进阶使用及模型类数据库迁移2
Django创建应用、ORM的进阶使用及模型类数据库迁移2
48 0
|
4月前
|
SQL 数据库 开发者
Python Web 开发: 什么是 Django ORM?如何使用它进行数据库操作?
Python Web 开发: 什么是 Django ORM?如何使用它进行数据库操作?
|
1月前
|
SQL API 数据库
一篇文章带你了解Django ORM操作
一篇文章带你了解Django ORM操作
20 0
|
5月前
|
SQL 缓存 数据库
10 Django模型 - 模型查询
10 Django模型 - 模型查询
41 0
|
5月前
|
SQL 关系型数据库 MySQL
07 Django模型 - ORM简介及MySQL数据库的使用
07 Django模型 - ORM简介及MySQL数据库的使用
36 0
|
4月前
|
Python
django orm 批量更新不同内容
网上存在很多相似文章,都是使用drf-extension,但是这个包其实只是批量更新的一种方法,就是全部更新一个内容,这完全不符合自己的需求。
25 1
|
7月前
|
SQL 存储 API
Django ORM详解:最全面的数据库处理指南
Django ORM详解:最全面的数据库处理指南
47 0