阅读目录
如何在 Django 终端打印 SQL 语句
如何在 Python 脚本中调用 Django 环境
操作方法
单表查询之神奇的下划线
ForeignKey 操作
ManyToManyField
聚合查询和分组查询
一, 如何在 Django 终端打印 SQL 语句
在 Django 项目的 settings.py 文件中, 在最后复制粘贴如下代码:
- LOGGING = {
- 'version': 1,
- 'disable_existing_loggers': False,
- 'handlers': {
- 'console':{
- 'level':'DEBUG',
- 'class':'logging.StreamHandler',
- },
- },
- 'loggers': {
- 'django.db.backends': {'handlers': ['console'],
- 'propagate': True,
- 'level':'DEBUG',
- },
- }
- }
即为你的 Django 项目配置上一个名为 django.db.backends 的 logger 实例即可查看翻译后的 SQL 语句.
- import os
- if __name__ == '__main__':
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "项目的名称下的 settings")
- import django
- django.setup() #先加载环境
from app01 import models 然后再调用项目中的 app 的 models
#下面就可以写 ORM 的操作方法
三, 一般操作
看专业的官网文档, 做专业的程序员! https://docs.djangoproject.com/en/1.11/ref/models/querysets/
1, 最常用的方法
- <1> all(): 查询所有结果
- <2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
- <3> get(**kwargs): 返回与所给筛选条件相匹配的对象, 返回结果有且只有一个, 如果符合筛选条件的对象超过一个或者没有都会抛出错误.
- <4> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
- <5> values(*field): 返回一个 ValueQuerySet-- 一个特殊的 QuerySet, 运行后得到的并不是一系列 model 的实例化对象, 而是一个可迭代的字典序列
- <6> values_list(*field): 它与 values()非常相似, 它返回的是一个元组序列, values 返回的是一个字典序列
- <7> order_by(*field): 对查询结果排序
- <8> reverse():
对查询结果反向排序, 请注意 reverse()通常只能在具有已定义顺序的 QuerySet 上调用 (在 model 类的 Meta 中指定 ordering 或调用 order_by() 方法).
<9> distinct():
从返回结果中剔除重复纪录(如果你查询跨越多个表, 可能在计算 QuerySet 时得到重复的结果. 此时可以使用 distinct(), 注意只有在 PostgreSQL 中支持按字段去重.
- <10> count(): 返回数据库中匹配查询 (QuerySet) 的对象数量.
- <11> first(): 返回第一条记录
- <12> last(): 返回最后一条记录
- <13> exists(): 如果 QuerySet 包含数据, 就返回 True, 否则返回 False
上面这些最常用的方法可对其返回的值进行分类:
返回 QuerySet 对象的方法有: all(),filter(),exclude(),order_by(),reverse(),distinct(),
特殊的 QuerySet:values() 返回一个可迭代的字典序列, values_list() 返回一个可迭代的元祖序列
返回具体对象的: get(),first(),last()
返回布尔值的方法有: exists()
返回数字的方法有: count()
2, 准备练习用的表单结构
- # 书
- class Book(models.Model):
- title = models.CharField(max_length=32)
- publish_date = models.DateField(auto_now_add=True)
- price = models.DecimalField(max_digits=5, decimal_places=2)
- memo = models.TextField(null=True)
- # 创建外键, 关联 publish
- publisher = models.ForeignKey(to="Publisher")
- # 创建多对多关联 author
- author = models.ManyToManyField(to="Author")
- def __str__(self):
- return self.title
- # 出版社
- class Publisher(models.Model):
- name = models.CharField(max_length=32)
- city = models.CharField(max_length=32)
- def __str__(self):
- return self.name
- # 作者
- class Author(models.Model):
- name = models.CharField(max_length=32)
- age = models.IntegerField()
- phone = models.CharField(max_length=11)
- detail = models.OneToOneField(to="AuthorDetail")
- def __str__(self):
- return self.name
- # 作者详情
- class AuthorDetail(models.Model):
- addr = models.CharField(max_length=64)
- email = models.EmailField()
3, 练习用的问题
查找所有书名里包含番茄的书
查找出版日期是 2017 年的书
查找出版日期是 2017 年的书名
查找价格大于 10 元的书
查找价格大于 10 元的书名和价格
查找 memo 字段是空的书
查找在机械的出版社
查找名字以牛开头的出版社
查找作者名字里面带 "小" 字的作者
查找年龄大于 30 岁的作者
查找手机号是 155 开头的作者
查找手机号是 155 开头的作者的姓名和年龄
查找书名是 "番茄物语" 的书的出版社
查找书名是 "番茄物语" 的书的出版社所在的城市
查找书名是 "番茄物语" 的书的出版社的名称
查找书名是 "番茄物语" 的书的所有作者
查找书名是 "番茄物语" 的书的作者的年龄
查找书名是 "番茄物语" 的书的作者的手机号码
查找书名是 "番茄物语" 的书的作者的地址
查找书名是 "番茄物语" 的书的作者的邮箱
四, 单表查询之神奇的双下划线
- models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取 id 大于 1 且 小于 10 的值
- models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取 id 等于 11,22,33 的数据
- models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
- models.Tb1.objects.filter(name__contains="ven") # 获取 name 字段包含 "ven" 的
- models.Tb1.objects.filter(name__icontains="ven") # icontains 大小写不敏感
- models.Tb1.objects.filter(id__range=[1, 3]) # id 范围是 1 到 3 的, 等价于 SQL 的 bettwen and
类似的还有: startswith,istartswith, endswith, iendswith
date 字段还可以:
models.Class.objects.filter(first_day__year=2017)
五, ForeignKey 操作
1, 正向查找
对象查找(跨表)
语法:
对象
.
关联字段. 字段
示例:
- book_obj = models.Book.objects.first() # 第一本书对象
- print(book_obj.publisher) # 得到这本书关联的出版社对象
- print(book_obj.publisher.name) # 得到出版社对象的名称
字段查找(跨表)
语法:
关联字段__字段
示例:
print(models.Book.objects.values_list("publisher__name"))
2, 反向操作
对象查找
语法: obj. 表名_set
示例:
- publisher_obj = models.Publisher.objects.first() # 找到第一个出版社对象
- books = publisher_obj.book_set.all() # 找到第一个出版社出版的所有书
- titles = books.values_list("title") # 找到第一个出版社出版的所有书的书名
字段查找
语法: 表名__字段
示例:
titles = models.Publisher.objects.values_list("book__title")
六, ManyToManyField(class RelatedManager)
"关联管理器" 是在一对多或者多对多的关联上下文中使用的管理器.
它存在于下面两种情况:
外键关系的反向查询
多对多关联关系
简单来说就是当 点后面的对象 可能存在多个的时候就可以使用以下的方法.
方法
create()
创建一个新的对象, 保存对象, 并将它添加到关联对象集之中, 返回新创建的对象.
- import datetime
- models.Author.objects.first().book_set.create(title="番茄物语", publish_date=datetime.date.today())
- add()
把指定的 model 对象添加到关联对象集中.
添加对象
- author_objs = models.Author.objects.filter(id__lt=3)
- models.Book.objects.first().authors.add(*author_objs)
添加 id
- models.Book.objects.first().authors.add(*[1, 2])
- set()
更新 model 对象的关联对象.
- book_obj = models.Book.objects.first()
- book_obj.authors.set([2, 3])
- remove()
从关联对象集中移除执行的 model 对象
- book_obj = models.Book.objects.first()
- book_obj.authors.remove(3)
- clear()
从关联对象集中移除一切对象.
- book_obj = models.Book.objects.first()
- book_obj.authors.clear()
注意:
对于 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()
注意:
对于所有类型的关联字段, add(),create(),remove()和 clear(),set()都会马上更新数据库. 换句话说, 在关联的任何一端, 都不需要再调用 save()方法.
七, 聚合查询和分组查询
1, 聚合
aggregate()是 QuerySet 的一个终止子句, 意思是说, 它返回一个包含一些键值对的字典.
键的名称是聚合值的标识符, 值是计算出来的聚合值. 键的名称是按照字段和聚合函数的名称自动生成出来的.
用到的内置函数:
from django.db.models import Avg, Sum, Max, Min, Count
示例:
- >>> from django.db.models import Avg, Sum, Max, Min, Count
- >>> models.Book.objects.all().aggregate(Avg("price"))
- {'price__avg': 13.233333}
如果你想要为聚合值指定一个名称, 可以向聚合子句提供它.
- >>> models.Book.objects.aggregate(average_price=Avg('price'))
- {'average_price': 13.233333}
如果你希望生成不止一个聚合, 你可以向 aggregate()子句中添加另一个参数. 所以, 如果你也想知道所有图书价格的最大值和最小值, 可以这样查询:
- >>> models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))
- {'price__avg': 13.233333, 'price__max': Decimal('19.90'), 'price__min': Decimal('9.90')}
2, 分组
我们在这里先复习一下 SQL 语句的分组.
我们使用原生 SQL 语句, 按照部分分组求平均工资:
select dept,AVG(salary) from employee group by dept; #employee 表名
ORM 查询:
- from django.db.models import Avg
- Employee.objects.values("dept").annotate(avg=Avg("salary").values(dept, "avg")
连表查询的分组:
SQL 查询:
select dept.name,AVG(salary) from employee inner join dept on (employee.dept_id=dept.id) group by dept_id;
ORM 查询:
- from django.db.models import Avg
- models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")
更多示例:
示例 1: 统计每一本书的作者个数
- >>> book_list = models.Book.objects.all().annotate(author_num=Count("author")) #也可以直接点 values('author_num')
- >>> for obj in book_list:
- ... print(obj.author_num)
- ...
- 2
- 1
- 1
示例 2: 统计出每个出版社买的最便宜的书的价格
- >>> publisher_list = models.Publisher.objects.annotate(min_price=Min("book__price"))
- >>> for obj in publisher_list:
- ... print(obj.min_price)
- ...
- 9.90
- 19.90
方法二:
- models.Book.objects.values("publisher__name").annotate(min_price=Min("price"))
- <QuerySet [{'publisher__name': '多多出版社', 'min_price': Decimal('9.90')}, {'publisher__name': '人民出版社', 'min_price': Decimal('19.90')}]>
示例 3: 统计不止一个作者的图书
- models.Book.objects.annotate(author_num=Count("author")).filter(author_num__gt=1)
- <QuerySet [<Book: 番茄物语>]>
示例 4: 根据一本图书作者数量的多少对查询集 QuerySet 进行排序
- models.Book.objects.annotate(author_num=Count("author")).order_by("author_num")
- <QuerySet [<Book: 香蕉物语>, <Book: 橘子物语>, <Book: 番茄物语>]>
示例 5: 查询各个作者出的书的总价格
- models.Author.objects.annotate(sum_price=Sum("book__price")).values("name", "sum_price")
- <QuerySet [{'name': '小精灵', 'sum_price': Decimal('9.90')},
- {'name': '小仙女', 'sum_price': Decimal('29.80')},
- {'name': '小魔女', 'sum_price': Decimal('9.90')}]>
来源: https://www.cnblogs.com/ManyQian/p/9210254.html