zoukankan      html  css  js  c++  java
  • ORM- 图书系统查询

    图书信息系统

    表结构设计

     1 #
     2 class Book(models.Model):
     3     title = models.CharField(max_length=32)
     4     publish_date = models.DateField(auto_now_add=True)
     5     price = models.DecimalField(max_digits=5, decimal_places=2)
     6     # 创建外键,关联publish
     7     publisher = models.ForeignKey(to="Publisher")
     8     # 创建多对多关联author
     9     author = models.ManyToManyField(to="Author")
    10   
    11 
    12   #可以直观的看的所查询的对象。在python中print自动调用str。
    13     def __str__(self):
    14         return self.title
    15 
    16 
    17 # 出版社
    18 class Publisher(models.Model):
    19     name = models.CharField(max_length=32)
    20     city = models.CharField(max_length=32)
    21 
    22     def __str__(self):
    23         return self.name
    24 
    25 
    26 # 作者
    27 class Author(models.Model):
    28     name = models.CharField(max_length=32)
    29     age = models.IntegerField()
    30     phone = models.IntegerField()
    31     detail = models.OneToOneField(to="AuthorDetail")
    32 
    33     def __str__(self):
    34         return self.name
    35 
    36 
    37 # 作者详情
    38 class AuthorDetail(models.Model):
    39     addr = models.CharField(max_length=64)
    40     email = models.EmailField()
    表结构设计

    简单示例

    单表查询(一张表)

    查询书名为番茄物语的书

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

    Q查询的另一种用法:适用于字段以字符串的形式出现
    from django.db.models import Q
    #定义“or”关系,不定义默认为“and”关系
    search_condition.connector="or"
    #示例一个Q对象
    filter_condition=Q()
    #“name”=“曹超”  此时的name是字符串
    filter_condition.children.append((“name”,“曹超”))
    
    #模糊过滤
    search_condition.children.append((search_field+"__contains",key_word))

    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: 橘子物语>]>
  • 相关阅读:
    node
    github
    [模块] pdf转图片-pdf2image
    python 15 自定义模块 随机数 时间模块
    python 14 装饰器
    python 13 内置函数II 匿名函数 闭包
    python 12 生成器 列表推导式 内置函数I
    python 11 函数名 迭代器
    python 10 形参角度 名称空间 加载顺序
    python 09 函数参数初识
  • 原文地址:https://www.cnblogs.com/caochao-/p/8343955.html
Copyright © 2011-2022 走看看