Django框架之ORM数据操作

数据库的核心操作就是对数据的增删改查,之前已经些了关于在Django中ORM的设置、映射等,接下来就开始对数据库进行操作。

python-django

0x00 基础操作

A 常用操作方法

  • all( ):查询所有结果
  • filter(**kwargs):查询包含条件的结果
  • get(**kwargs):返回条件匹配的对象,如果超过1个结果或者没有,则报错
  • exclude(**kwargs):返回与条件不匹配的对象,即排除
  • values(*field):返回一个ValueQuerySet,生成一个包含field的可迭代的字典序列
  • values_list(*field):返回一个元组元组序列
  • order_by(*field):对查询结果进行排序
  • reverse( ):对查询结果反向排序,只能对已定义顺序的QuerySet中调用
  • distinct( ):从查询结果中删除重复记录
  • count( ):返回查询查询结果的对象数量
  • first( ):返回第一个记录
  • last( ):返回最后一个记录
  • exists( ):如果QuerySet包含数据,就返回True,否则返回False

B 常用方法之双下划线

在Django查询条件中没有”>”、”<“等类似符号,也没有类似”between and”等关键字,而为了使用这类方法则需要用到Django中提供的双下划线方法。

  • id__lt=10, id__gt>3:id小于10且大于3的值
  • id__in=[1,2,5]:id在列表范围内的值
  • name__contains=”moe”:name字段中包含”moe”字段的
  • name__incontains=”moe”:大小写不敏感
  • id__range=[1,5]:id范围在1到5的,等价于between…and…
  • date__year=2017:为2017年的,仅适用于date字段

其余还有类似于startswith、instartswith、endwith、isendswith。

0x01 连表查询

Django中数据表格结果如下:

from django.db import models

# Create your models here.
class Publisher(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=12)


class Book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=64, unique=True)
    price = models.IntegerField(default=15)
    # 一对多的关系可以使用ForeignKey来完成
    # publiser = models.ForeignKey(to=Publisher,on_delete=models.CASCADE)
    publiser = models.ForeignKey(to=Publisher)

class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32,unique=True)
    # 使用ManyToMany来创建多对多的关系
    book = models.ManyToManyField('Book')

A-ForeignKey查询操作

a_正向查找

对象查找法:

ret = models.Book.objects.first()
print(ret.publiser.name)
# 等价于
p = models.Book.objects.first().publiser.name
print(p)

双下划线查询

ret = models.Book.objects.values_list("publiser__name")
for i in ret:
    print(i)

b_反向查询

对象查找法

用法:表明_set

ret = models.Publisher.objects.first().book_set.all()
print(ret)

双下划线查询

ret = models.Publisher.objects.filter(id=1).values_list("book__name")
print(ret)

B-ManyToManyField操作

“关联管理器”(class RelatedManager)是在一对多或者多对多的关联上下文中使用的管理器。

它存在于下面两种情况:

  1. 外键关系的反向查询
  2. 多对多关联关系

简单来说就是当点后面的对象可能存在多个的时候就可以使用以下的方法。

create( )方法

# 给出版社添加一本书
    models.Publisher.objects.get(id=2).book_set.create(name='newboo812', price='812')
    # 创建一本新的书
    models.Book.objects.create(name='boodandu', price='123', publiser_id='4')

add( )方法

    aut_obj = models.Author.objects.first()

    # 给没有作者的书 添加一个作者
    res = models.Book.objects.values('id', 'author__name')
    for i in res:
        if i['author__name'] is None:
            print(i['id'])

    models.Book.objects.get(id = 5).author_set.add(aut_obj)

set( )方法

models.Book.objects.get(id = 1).author_set.set([5,4,3])

remove( ) 方法

models.Book.objects.get(id = 1).author_set.remove(5)

clear( )方法

models.Book.objects.get(id = 1).author_set.clear()

对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。

0x02 聚合查询与分组查询

a_聚合查询

如果要对某一列进行操作,如计算平均值、总数、最大值、最小值等,那么则需要进行聚合查询,使用的关键字位 aggregate( ) ,其返回一个具有聚合查询标识符及值的字典。

    from django.db.models import Avg, Sum, Max, Min, Count
    
    res = models.Book.objects.aggregate(Avg('price'))
    print(res)

    #{'price__avg': 374.25}

在aggregate( )中,也可以批量进行查询。

    res = models.Book.objects.aggregate(Avg('price'),Count('id'),Max('price'),Min('price'))
    print(res)
    
    # {'id__count': 8, 'price__min': 6, 'price__max': 2436, 'price__avg': 374.25}

b_分组查询

分组查询即SQL中的group by语句,进行分类,其使用的函数为annotate( )。

from django.db.models import Avg, Sum, Max, Min, Count

# 统计每本书有几个作者
res = models.Book.objects.values('name').annotate(aut_num = Count("author")).values('name','aut_num')

其中第一个values( )表示以什么进行分组(即group by xxx),第二个values( ),表示最后取值的东西(select xxx)。

 # 统计出每个出版社买的最便宜的书的价格
res = models.Publisher.objects.values('name').annotate(low_price = Min('book__price')).values('name','low_price')
# 统计不止一个作者的图书
res = models.Book.objects.values('name').annotate(aut_num = Count('author')).filter(aut_num__gt=1)
# 查询各个作者出的书的总价格
res = models.Author.objects.values('name').annotate(sum_pri = Sum('book__price')).values('name','sum_pri')

0x03 F查询和Q查询

a_F查询

之前的查询条件编写时,在对比某个字段时候,只能与固定值进行lt、gt等操作,那么如何在两个字段之间进行比较呢?或者如何对某个字段进行操作呢,则需要用到F查询。

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)

进阶操作,给所有书后面都添加“第一版”。

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(")")))

在使用Concat时候,一定记得使用Value进行操作,无法链接。

b_Q查询

使用filter( )进行条件筛选时候,可以使用多个条件进行筛选仅仅有“和”的意思,但是如果想使用“或”等条件进行筛选,则需要使用Q查询。

from django.db.models import Q

 # 查询书名是bo1或者book1的书
models.Book.objects.filter(Q(name='bo1')|Q(name='book1'))

在Q查询中,可以使用|来表示“OR”,&表示“AND”,~表示“反选”。

# 查询作者名字是小仙女并且不是2018年出版的书的书名

models.Book.objects.filter(Q(author__name="小仙女") & ~Q(publish_date__year=2018)).values_list("title")

在filter中,也可以使用Q查询和普通查询一起进行条件筛选,但是Q查询一定要放前面。

# 查询作者名字是小仙女并且不是2018年出版且书名带有AA的书的书名

models.Book.objects.filter(Q(author__name="小仙女") & ~Q(publish_date__year=2018),title__contains="AA").values_list("title")

发表评论