图书信息系统

表结构设计

# 书
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)
# 创建外键,关联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.IntegerField()
detail = models.OneToOneField(to="AuthorDetail") def __str__(self):
return self.name # 作者详情
class AuthorDetail(models.Model):
addr = models.CharField(max_length=64)
email = models.EmailField()

普通查询练习

查找所有书名里包含番茄的书
查找出版日期是2017年的书
查找出版日期是2017年的书名
查找价格大于10元的书
查找价格大于10元的书名和价格
查找memo字段是空的书

查找在北京的出版社
查找名字以沙河开头的出版社

查找作者名字里面带“小”字的作者
查找年龄大于30岁的作者
查找手机号是155开头的作者
查找手机号是155开头的作者的姓名和年龄

查找书名是“番茄物语”的书的出版社
查找书名是“番茄物语”的书的出版社所在的城市
查找书名是“番茄物语”的书的出版社的名称

查找书名是“番茄物语”的书的所有作者
查找书名是“番茄物语”的书的作者的年龄
查找书名是“番茄物语”的书的作者的手机号码

查找书名是“番茄物语”的书的作者的地址
查找书名是“番茄物语”的书的作者的邮箱

简单示例

单表查询

查询书名为番茄物语的书

>>> models.Book.objects.filter(title="番茄物语")
<QuerySet [<Book: 番茄物语>]>

一对多查询

查询id为1的书的出版社所在的城市

>>> models.Book.objects.get(id=1).publisher.city
'北京'

查询id为1的出版社的出版的所有书籍(反向查找)

>>> models.Publisher.objects.get(id=1).book_set.all()
<QuerySet [<Book: 番茄物语>, <Book: 香蕉物语>]>

一对一查询

查询小精灵作者的邮箱

>>> models.Author.objects.get(name="小精灵").detail.email
'1@1.com'

查询所有addr="快乐星球"的作者姓名

>>> author_details = models.AuthorDetail.objects.filter(addr="快乐星球")
>>> for obj in author_details:
... print(obj.author.name)
小仙女
小魔女

多对多查询

查询番茄物语所有作者的姓名和邮箱(正向查找)

>>> models.Book.objects.get(title="番茄物语").author.all()
<QuerySet [<Author: 小精灵>, <Author: 小仙女>]>
>>> for obj in author_list:
... print(obj.name, obj.detail.email)
...
小精灵 1@1.com
小仙女 2@2.com

查询小仙女出版的所有书籍

>>> models.Author.objects.get(name="小仙女").book_set.all()
<QuerySet [<Book: 番茄物语>, <Book: 橘子物语>]>

了不起的双下划线

查询沙河出版社出版的所有书籍的名称和价格

(正向查)

>>> models.Book.objects.filter(publisher__name="沙河出版社").values_list("title", "price")
<QuerySet [('番茄物语', Decimal('9.90')), ('香蕉物语', Decimal('9.90'))]>

反向查

>>> models.Publisher.objects.get(name="沙河出版社").book_set.all().values_list("title", "price")
<QuerySet [('番茄物语', Decimal('9.90')), ('香蕉物语', Decimal('9.90'))]>

双下划线反查

>>> models.Publisher.objects.filter(name="沙河出版社").values_list("book__title", "book__price")
<QuerySet [('番茄物语', Decimal('9.90')), ('香蕉物语', Decimal('9.90'))]>

查询小仙女出版的所有书籍名称

正向查

>>> models.Book.objects.filter(author__name="小仙女").values_list("title")
<QuerySet [('番茄物语',), ('橘子物语',)]>

反向查

>>> models.Author.objects.get(name="小仙女").book_set.all().values_list("title")
<QuerySet [('番茄物语',), ('橘子物语',)]>

双下划线反查

>>> models.Author.objects.filter(name="小仙女").values_list("book__title")
<QuerySet [('番茄物语',), ('橘子物语',)]>

查询沙河出版社出版的书籍的书名和作者姓名

正向查

>>> models.Book.objects.filter(publisher__name="沙河出版社").values_list("title", "author__name")
<QuerySet [('番茄物语', '小精灵'), ('番茄物语', '小仙女'), ('香蕉物语', '小魔女')]>

反向查

>>> models.Publisher.objects.filter(name="沙河出版社").values_list("book__title", "book__author__name")
<QuerySet [('番茄物语', '小精灵'), ('番茄物语', '小仙女'), ('香蕉物语', '小魔女')]>

双下划线反向查

>>> models.Publisher.objects.get(name="沙河出版社").book_set.all().values_list("title", "author__name")
<QuerySet [('番茄物语', '小精灵'), ('番茄物语', '小仙女'), ('香蕉物语', '小魔女')]>

补充

查询memo为空的所有书

>>> models.Book.objects.filter(memo__isnull=True)

聚合查询和分组查询

聚合

aggregate()QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。

示例:

>>> 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')}

分组

为调用的QuerySet中每一个对象都生成一个独立的统计值

示例1:统计每一本书的作者个数

>>> book_list = models.Book.objects.all().annotate(author_num=Count("author"))
>>> 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')}]>

F查询和Q查询

F查询

在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?

Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。

示例1:

查询评论数大于收藏数的书籍

from django.db.models import F
models.Book.objects.filter(commnet_num__lt=F('keep_num'))

Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。

models.Book.objects.filter(commnet_num__lt=F('keep_num')*2)

修改操作也可以使用F函数,比如将每一本书的价格提高30元

models.Book.objects.all().update(price=F("price")+30)

引申:

如果要修改char字段咋办?

如:把所有书名后面加上(第一版)

>>> from django.db.models.functions import Concat
>>> from django.db.models import Value
>>> models.Book.objects.all().update(title=Concat(F("title"), Value("("), Value("第一版"), Value(")")))

Q查询

filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象

示例1:

查询作者名是小仙女或小魔女的

models.Book.objects.filter(Q(authors__name="小仙女")|Q(authors__name="小魔女"))

你可以组合& 和|  操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询。

示例:查询作者名字是小仙女并且不是2018年出版的书的书名。

>>> models.Book.objects.filter(Q(author__name="小仙女") & ~Q(publish_date__year=2018)).values_list("title")
<QuerySet [('番茄物语',)]>

查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。

例如:查询出版年份是2017或2018,书名中带物语的所有书。

>>> models.Book.objects.filter(Q(publish_date__year=2018) | Q(publish_date__year=2017), title__icontains="物语")
<QuerySet [<Book: 番茄物语>, <Book: 香蕉物语>, <Book: 橘子物语>]>

Django ORM训练专题的更多相关文章

  1. Python学习(三十五)—— Django之ORM训练专题

    图书管理系统 一.表结构设计 # 书 class Book(models.Model): title = models.CharField(max_length=32) publish_date = ...

  2. Django(ORM查询2)

    day70 ORM训练专题 :http://www.cnblogs.com/liwenzhou/articles/8337352.html 内容回顾     1. ORM         1. ORM ...

  3. django orm总结[转载]

    django orm总结[转载] 转载地址: http://www.cnblogs.com/linjiqin/archive/2014/07/01/3817954.html 目录1.1.1 生成查询1 ...

  4. Django ORM - 001 - 外键表查询主表信息

    开始用Django做web开发,我想大家都会遇到同样的问题,那就是如何高效快速的查询需要的数据,MVC都很简单,但是ORM折腾起来就有些费时间,我准备好好研究下Django ORM,所以会有一个系列的 ...

  5. Django ORM 中的批量操作

    Django ORM 中的批量操作 在Hibenate中,通过批量提交SQL操作,部分地实现了数据库的批量操作.但在Django的ORM中的批量操作却要完美得多,真是一个惊喜. 数据模型定义 首先,定 ...

  6. Django ORM 查询管理器

    Django ORM 查询管理器 ORM 查询管理器 对于 ORM 定义: 对象关系映射, Object Relational Mapping, ORM, 是一种程序设计技术,用于实现面向对象编程语言 ...

  7. Django ORM模型的一点体会

    作者:Vamei 出处:http://www.cnblogs.com/vamei 严禁转载. 使用Python的Django模型的话,一般都会用它自带的ORM(Object-relational ma ...

  8. 数据库表反向生成(二) Django ORM inspectdb

    在前一篇我们说了,mybatis-generator反向生成代码. 这里我们开始说如何在django中反向生成mysql model代码. 我们在展示django ORM反向生成之前,我们先说一下怎么 ...

  9. Django ORM那些相关操作

    一般操作 https://docs.djangoproject.com/en/1.11/ref/models/querysets/         官网文档 常用的操作 <1> all() ...

随机推荐

  1. 逆序对 inversion

      评测传送门 [问题描述] 有一个1 − n的排列,你会依次进行m次操作,第i次操作表示为(x i , y i ),交换以这两个 值为下标的元素,每次操作有一半的概率成功,你需要求出最后序列的逆序对 ...

  2. Python练习-有点儿意思的用户登录

    Alex大神的需求(说实话他需求真特么多,真难满足他): 编写一个用户登陆接口:输入用户名密码,认证成功后显示欢迎信息,输错三次后锁定; # 编辑者:闫龙 #用户登录功能输入3次以上会被锁定:为了方便 ...

  3. sql 通过分数字段倒排获取名次的方法

    row_number() over(order by sort desc) 应用场景: 比如学员成绩表中有userid,username,sorce登字段,需要取出学员成绩的名次:表中没有名次字段,只 ...

  4. WeX5入门之HelloWorld

    学习目标:数据双向绑定 在ui2上右键 新建一个应用 然后会出现一个目录 右键hello 在创建页面 选择标准的空白模板 并起一个名 自动生成这两个文件 建立一个input组件 再建一个output组 ...

  5. solr4.10.3部署到tomcat——(十)

    0. 准备环境:

  6. nginx 的多域名多https转发设置方法【转】

    version: 1.1(fixed) 修正一些错误基本环境:/etc/nginx/nginx.conf #保持/etc/nginx/ssl/    #ssl认证文件/etc/nginx/site-a ...

  7. c++ 类的构造顺序

    在单继承的情况下,父类构造先于子类,子类析构先于父类,例: class A { public: A() { cout << "A" << endl; } ~ ...

  8. mysql高可用架构 -> MHA配置VIP漂移-05

    VIP漂移的两种方式 1)通过keepalived的方式,管理虚拟IP的漂移 2)通过MHA自带脚本方式,管理虚拟IP的漂移 MHA脚本方式 虚拟ip漂移的脚本下载地址 -> wget http ...

  9. Bootstrap FileInput中文API文档

    Bootstrap FileInput中文API整理 这段时间做项目用到bootstrap fileinput插件上传文件,在用的过程中,网上能查到的api都不是很全,所以想着整理一份比较详细的文档, ...

  10. 简单ORACLE分区表、分区索引

    前一段听说CSDN.COM里面很多好东西,同事建议看看合适自己也可以写一写,呵呵,今天第一次开通博客,随便写点东西,就以第一印象分区表简单写第一个吧. ORACLE对于分区表方式其实就是将表分段存储, ...