9_19模型层的操作

一。配置settings。

  如果是queryset对象 那么可以点query直接查看该queryset的内部sql语句

  将以下代码放入settings中。就可以实现当使用orm时查看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过滤查询中,有基于双下划线的查询,可以节省时间。

  1.大于:__gt

  可以匹配大于这个数值的数:

res = models.Book.objects.filter(price__gt=89)

  2.小于__lt

  匹配小于这个数值的数据:

res = models.Book.objects.filter(price__lt=89)

  3.大于等于__gte

  匹配大于等于这个数值的数:

res = models.Book.objects.filter(price__gte=89)

  4.小于等于__lte

  匹配小于等于这个数值的数:

res = models.Book.objects.filter(price__lte=89)

  5。__in

  匹配在后面这个数列中的所有值的数据/。

res = models.Book.objects.filter(price__in=[89,123,454])

  6.__range(x,y)

  匹配在这个范围中的所有数据。包括头和尾。

res = models.Book.objects.filter(price__range=[55,123])

  7.__contains

  模糊匹配,字段中包函这个字段的数据。

res = models.Book.objects.filter(title__contains='p')

  这个匹配区分大小写。下面这个方法不区分。

  8.__icontains

res = models.Book.objects.filter(title__icontains='P')

  9.__startswith

  匹配开头时这个数值的数据

res = models.Book.objects.filter(title__startswith='')

  10.__endswith

  匹配结尾这个数值的数据

res = models.Book.objects.filter(title__endswith='')

  11.__year

  匹配时间数据类型中年份为该年的数据:

res = models.Book.objects.filter(publish_date__year=2019)
res = models.Book.objects.filter(publish_date__month=9)

  当然,其中还有其他过滤日期的方法。

(自己理解): 

  对于像onetoonefield,foreign,manytomany等字段,都是 有母子之分的。

  也就是说这个虚拟字段在哪个表里,哪个表就是子表。

  而我们把根据子表查询母表时的动作叫正向查询。

    正向查询都是按找字段名查找。

  根据母表数据查询子表数据的动作叫反向查询。

    反向查询都是按照表名小写_set查找。

  得到的结果就是那个表的对象。

  而在1对1 的时候不需要加_set,只需要小写就行。

三。关于外键的增删改。

  1.一对多

  增:

  可以按照id值传入外键:

models.Book.objects.create(title='三国演义',price=189.99,publish_id=1)

  也可以将那个对象传入:

publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='红楼梦',price=999.99,publish=publish_obj)

  改:

  将id数字传入:

models.Book.objects.filter(pk=1).update(publish_id=3)

  可以将对象传入:

publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)

  删:

  删除的时候,默认都是级联操作。也即是这个数据删除了它所关联的外键也删除。

models.Publish.objects.filter(pk=2).delete()

  2,多对多字段的增删改。

  增:

  增加操作多借助于add(),是一个正对query对象的方法。

#要给主键为1的书籍添加两个作者
book_obj = models.Book.objects.filter(pk=1).first()
print(book_obj.authors)  
# 对象点击多对多虚拟字段 会直接跨到多对多的第三张表
book_obj.authors.add(1)
book_obj.authors.add(2,3)

  add()也支持传入对象,添加对象:

author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.add(author_obj)
book_obj.authors.add(author_obj1,author_obj2)

  改:

  改操作借助于函数set()

  set支持传入数据:

将主键为1的书籍对象 作者修改为2,3
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.set([2,])
book_obj.authors.set([2,3])

  也支持传入对象:

author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.set([author_obj,])
book_obj.authors.set([author_obj, author_obj1, author_obj2])

  但是set中要是一个可迭代对象。但不能混合使用。

  删:

  删除操作使用的是remove函数:
  可以支持数字:

book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.remove(3)
book_obj.authors.remove(1,2)

  也支持对象:

author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.remove(author_obj)
book_obj.authors.remove(author_obj1,author_obj2)

  除了remove之外,还可以使用clear,将这个对象的所有联系都清空。

book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.clear()  # 清空当前书籍与作者的所有关系

  这些操作也支持_set反向操作。

四。基于对象的跨表查询。

  多表查询的方法可以先将一个条件对象找到,通过他下面的虚拟字段或者起子表_set的方法获取表对象,在提取想要的信息。

  例子:

    查询作者是jason的家庭住址
    author_obj = models.Author.objects.filter(name='jason').first()
    print(author_obj.author_detail.addr)


    查询出版社是东方出版社出版的书籍
    publish_obj = models.Publish.objects.filter(name='东方出版社').first()
    # print(publish_obj.book_set)  # app01.Book.None
    print(publish_obj.book_set.all())

    查询作者是jason的写过的所有的书籍
    author_obj = models.Author.objects.filter(name='jason').first()
    print(author_obj.book_set)  # app01.Book.None
    print(author_obj.book_set.all())

  注意,在获取了表之后,可以继续对其使用对表对象使用的一切方法。

五。基于双下划线的跨表查询。

  双下划线作用于任何关于表的字段的获取,其可以获取另一个它关联的表的字段数据。

  双下划线不分子母表。

  values()函数相当于原生sql语句中的select后面的值。其返回的也是一个queryset对象。其中传入的是字段

  例子:

查询jason这个作者的年龄和手机号
正向
res = models.Author.objects.filter
(name='jason').values('age','author_detail__phone') print(res) 反向 res1 = models.AuthorDetail.objects.filter
(author__name='jason').values('phone','author__age')

  例子2:

# 查询手机号是130的作者年龄
# 正向
res = models.AuthorDetail.objects.filter(phone=130).values('author__age')
print(res)
# 反向
res1 = models.Author.objects.filter(author_detail__phone=130).values('age')

  只要表里有外键字段,就可以无限跨多张表:

res1 = models.Book.objects.filter(pk=1).values('外键字段1__外键字段2__外键字段3__普通字段')

六。聚合查询:

  聚合查询和sql原生语句差不都:

  1.Sum()求和

  2.Avg()求平均值

  3.Count()计数

  4.Max()最大值

  5.Min()最小值

from django.db.models import Max,Min,Count,Avg,Sum
res = models.Book.objects.aggregate(Sum('price'))
res1 = models.Book.objects.aggregate(Avg('price'))
res2 = models.Book.objects.aggregate(Count('price'))
res3 = models.Book.objects.aggregate(Max('price'))
res4 = models.Book.objects.aggregate(Min('price'))
res5 = models.Book.objects.aggregate(Max('price'),  
  Min('price'),Count('pk'),Avg('price'),Sum('price'))

  其中aggregate就是使用聚合函数,其中也支持双下划线跨表查询。

七。分组查询。

  分组查询使用annotate()

  这个函数中可以使用聚合函数,使用聚合函数产生的结果可以给他起别名,再通过value展示。

res = models.Publish.objects.annotate
  (mmp = Min('book__price')).values('name','mmp')

  如果annotate之前不使用value进行指定字段,就将这个表的id作为分组对象。指定了value就将value中的字段进行分组。

  例子:

查询各个作者出的书的总价格
res = models.Author.objects.annotate(
  sp=Sum('book__price')).values('name','sp')

八。f查询与q查询。

  f。将数据库中的数据取出转化成可操作的。

  当你需要查询一个值的数据两端都是数据库中的值时。可以使用f将后面那个值包起来,这样系统会根据记录一条条比对:

from django.db.models import F
res = models.Book.objects.filter(kucun__gt=F('maichu'))

# 将书籍库存数全部增加1000
models.Book.objects.update(kucun=F('kucun')+1000)

  这个操作可以将数据库中本来的数据拿出来使用f操作进行转换,转换成课进行操作的对象:

 # 把所有书名后面加上'新款'
from django.db.models.functions import Concat
from django.db.models import Value
ret3 = models.Book.objects.update
    (title=Concat(F('title'), Value('新款')))
models.Book.objects.update(title = F('title')+'新款')  # 不能这么写

  其中concat就是拼接字符串操作(再数据库中),而value就是将字符串转化成可操作的数据。

  q。将数据库的数据取出,转化成可进行逻辑比较的。

  如果需要将两个字段的数据一起匹配时可以使用q进行操作。

  例子:

from django.db.models import Q
查询书籍名称是三国演义或者价格是444.44
res = models.Book.objects.filter(title='三国演义',price=444.44)  # filter只支持and关系
res1 = models.Book.objects.filter(Q(title='三国演义'),Q(price=444))  # 如果用逗号 那么还是and关系
res2 = models.Book.objects.filter(Q(title='三国演义')|Q(price=444))
res3 = models.Book.objects.filter(~Q(title='三国演义')|Q(price=444))
# 非操作。

  在q前面加上~表示非操作。

  衍生:

  当需要使用字符串作为表字段名进行操作的时候,可以使用q。

  也就是说不会提前知道字段名,只知道该字段是个字符串。

    # 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)

补充:

  1.在一对一字段中OnoToOneField操作可以用ForeignKey代替(ForeignKey(unique=True))

  2.虚拟字段除了关联第三张表之外,还能帮助orm跨表查询。

原文地址:https://www.cnblogs.com/LZXlzmmddtm/p/11552765.html