Django ORM操作练习 以及 F和Q的使用方法 双下条件等等

表关系:

from django.db import models
# Create your models here.


class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    # 与AuthorDetail建立一对一的关系
    authorDetail = models.OneToOneField(to="AuthorDetail", on_delete=models.CASCADE)


class AuthorDetail(models.Model):
    nid = models.AutoField(primary_key=True)
    birthday = models.DateField()
    telephone = models.BigIntegerField()
    addr = models.CharField(max_length=64)


class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()


class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    publishDate = models.DateTimeField()
    price = models.DecimalField(max_digits=5, decimal_places=2)

    # 与Publish建立一对多的关系,外键字段建立在多的一方
    publish = models.ForeignKey(to="Publish", to_field="nid", on_delete=models.CASCADE)
    # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
    authors = models.ManyToManyField(to='Author', )

练习:

一、基于对象查询(子查询)

  1、正向查询:出版社与书籍属于一对多关系,关系字段在书籍表中,通过书籍表找出版社属于正向查询

    # 查询书籍名称是python的出版社名称,对象点字段的形式查询即可(obj.publish.name)
    ret = models.Book.objects.filter(title='python').first().publish.name
    print(ret)

  2、反向查询: 出版社与书籍属于一对多关系,关系字段在书籍表中,通过出版社表找书籍表属于反向查询

# 查询出版社id为1的出版社,出版过哪些书籍。表名加__set
    ret = models.Publish.objects.filter(nid=1).first().book_set.values('title')
    print(ret)

二、基于QuerySet和"__"查询(连表查询)

  1、正向查询:出版社与书籍属于一对多关系,关系字段在书籍表中,通过书籍表找出版社属于正向查询

    # 查询python这本书籍的出版社的邮箱:values('关联字段__字段')
    ret = models.Book.objects.filter(title='python').values('publish__email')
    print(ret)
  ret = ret = models.Publish.objects.filter(book__title='python').values('email')
  print(ret)

  2、反向查询:同理,通过出版社表找书籍表属于反向查询

# 查询永丰出版社出版过的书籍名称:values('表名__字段')
    # 方法一:
    ret = models.Publish.objects.filter(name='永丰出版社').values('book__title')
    print(ret)

    # 方法二 
    ret = models.Book.objects.filter(publish__name='永丰出版社').values('title')
    print(ret)

三、聚合查询

  aggregate()QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典,而不是QuerySet和一个具体的对象

from django.db.models import Count, Avg, Sum, Max, Min
    # 查询所有书籍的价格总和
    ret = models.Book.objects.aggregate(Sum('price'))
    print(ret)

四、分组查询:annotate前面是什么,就按照什么分组

    # 查询永丰出版社的所有书籍的平均价格
    ret = models.Publish.objects.values('name').annotate(avg=Avg('book__price')).values('name', 'avg').filter(name='永丰出版社')
    print(ret)

ORM语句与SQL语句对照:

   gt大于、lt小于、order_by排序

    # 查询书籍平均价格低于100的出版社:filter('字段名__lt')
    ret = models.Publish.objects.values('name').annotate(avg=Avg('book__price')).values('name', 'avg').filter(avg__lt=100)
    print(ret)
    # 按照书籍平均价格对出版社进行排序
    ret = models.Publish.objects.values('name').annotate(avg=Avg('book__price')).values('name', 'avg').order_by('avg')
    print(ret)
 
F和Q:
  F查询:

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

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

示例1:

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

from django.db.models import F
models.Book.objects.filter(commnet_num__gt=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: 橘子物语>]>
 
  Q的高级用法:
    q = Q()
    q.connector = 'or'  # 修改查询条件的关系   默认是and
    q.children.append(('title__contains','三国演义'))  # 往列表中添加筛选条件 ,接收一个元祖(字段,值)
    q.children.append(('price__gt',444))  # 往列表中添加筛选条件
    res = models.Book.objects.filter(q)  # filter支持你直接传q对象  但是默认还是and关系
    print(res)

  双下条件:

__exact 精确等于 like 'aaa'
 __iexact 精确等于 忽略大小写 ilike 'aaa'
 __contains 包含 like '%aaa%'
 __icontains 包含 忽略大小写 ilike '%aaa%',但是对于sqlite来说,contains的作用效果等同于icontains。
__gt 大于
__gte 大于等于
__lt 小于
__lte 小于等于
__in 存在于一个list范围内
__startswith 以...开头
__istartswith 以...开头 忽略大小写
__endswith 以...结尾
__iendswith 以...结尾,忽略大小写
__range 在...范围内
__year 日期字段的年份
__month 日期字段的月份
__day 日期字段的日
__isnull=True/False
原文地址:https://www.cnblogs.com/aizhinong/p/12305640.html