Django--ORM多表操作

一 创建表模型

假设:

  作者模型:一个作者有姓名和年龄。

  作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)

  出版商模型:出版商有名称,所在城市以及email。

  书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-                            many);一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。

from django.db import models


# Create your models here.
class Publish(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=32)
    email = models.EmailField()


class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    sex = models.IntegerField()
    authordetail = models.OneToOneField(to='AuthorDetail', to_field='id')


class AuthorDetail(models.Model):
    id = models.AutoField(primary_key=True)
    phone = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)


class Book(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish = models.ForeignKey(to=Publish, to_field='id')

    authors = models.ManyToManyField(to=Author)

    def __str__(self):
        return self.name

二 增删改查

import os

if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day77.settings")
    import django

    django.setup()

    from app01.models import *

    # 一对多新增数据
    # 添加一本北京出版社出版的书
    # 第一种方式
    # ret=Book.objects.create(name='红楼梦',price=34.5,publish_id=1)
    # print(ret.name)
# 第二种方式,存对象publish=出版社的对象,存到数据库,是一个id # publish=Publish.objects.get(id=1) # pk是主键,通过主键查找 # publish=Publish.objects.get(pk=1) # publish = Publish.objects.filter(pk=2).first() # ret = Book.objects.create(name='西游记', price=34.5, publish=publish) # print(ret.name)

# 一对多修改数据 # book=Book.objects.get(pk=1) # # book.publish=出版社对象 # book.publish_id=2 # book.save()
# 方式二 # book=Book.objects.filter(pk=1).update(publish=出版社对象) # book=Book.objects.filter(pk=1).update(publish_id=1)

# 多对多新增 # 为红楼梦这本书新增一个叫lqz,egon的作者 # lqz=Author.objects.filter(name='lqz').first() # egon=Author.objects.filter(name='egon').first() # book=Book.objects.filter(name='红楼梦').first() # # add 添加多个对象 # book.authors.add(lqz,egon) # add添加作者id # book.authors.add(1,2)

#删除 remove,可以传对象,可以传id,可以传多个,不要混着用 # book.authors.remove(lqz) # book.authors.remove(2) # book.authors.remove(1,2)

# clear清空所有 # book.authors.clear() # set,先清空,在新增,要传一个列表,列表内可以是, id,也可以是对象 # book.authors.set([lqz,]) # ********这样不行,因为它打散了传过去了,相当于book.authors.set(lqz) # book.authors.set(*[lqz,])

三 基于对象的跨表查询

 '''
    一对一
    正向   author---关联字段在author--->authordetail   ------>  按字段
    反向   authordetail------关联字段在author--->author  -----> 按表名小写
    
    '''
    # 查询lqz作者的手机号   正向查询
    # author=Author.objects.filter(name='lqz').first()
    # # author.authordetail 就是作者详情的对象
    # authordetail=author.authordetail
    # print(authordetail.phone)
   # 查询地址是 :山东 的作者名字   反向查询
   # authordetail=AuthorDetail.objects.filter(addr='山东').first()
   # # authordetail.author  这是作者对象
   # author=authordetail.author
   # print(author.name)

    #一对多
    '''
    一对多
    正向   book---关联字段在book--->publish   ------>  按字段
    反向   publish------关联字段在book--->book  -----> 按表名小写_set.all()
    '''
    # 正向 查询红楼梦这本书的出版社邮箱
    # book=Book.objects.filter(name='红楼梦').first()
    # # book.publish  就是出版社对象
    # pulish=book.publish
    # print(pulish.email)
    # 反向  查询地址是北京 的出版社出版的图书
    # publish=Publish.objects.filter(addr='北京').first()
    # # publish.book_set.all()  拿出所有的图书
    # books=publish.book_set.all()
    # # 统计一下条数
    # books=publish.book_set.all().count()
    # print(books)

    '''
    多对多
    正向   book---关联字段在book--->author   ------>  按字段.all()
    反向   author------关联字段在book--->book  -----> 按表名小写_set.all()
    '''
    #查询红楼梦这本书所有的作者
    # book=Book.objects.filter(name='红楼梦').first()
    # book.authors.all()  #是所有的作者,是一个queryset对象,可以继续点
    # print(book.authors.all())

    # 查询lqz写的所有书
    # lqz=Author.objects.filter(name='lqz').first()
    # books=lqz.book_set.all()
    # print(books)

    # 连续跨表
    # 查询红楼梦这本书所有的作者的手机号
    # book=Book.objects.filter(name='红楼梦').first()
    # authors=book.authors.all()
    # for author in authors:
    #     authordetail=author.authordetail
    #     print(authordetail.phone)
  基于对象的查询---是子查询也就是多次查询

四 基于双下划线的查询

 # 一对一
    # 查询lqz作者的手机号   正向查询  跨表的话,按字段
    # 以author表作为基表
    # ret=Author.objects.filter(name='lqz').values('authordetail__phone')
    # print(ret)
# 以authordetail作为基表 反向查询,按表名小写 跨表的话,用表名小写 # ret=AuthorDetail.objects.filter(author__name='lqz').values('phone') # print(ret)
# 查询lqz这个作者的性别和手机号 # 正向 # ret=Author.objects.filter(name='lqz').values('sex','authordetail__phone') # print(ret) # 查询手机号是13888888的作者性别 # ret=Author.objects.filter(authordetail__phone='13888888').values('sex') # print(ret) # ret=AuthorDetail.objects.filter(phone='13888888').values('author__sex') # print(ret) # 基于双 下划线的一对多查询 # 查询出版社为北京出版社出版的所有图书的名字,价格 # ret=Publish.objects.filter(name='北京出版社').values('book__name','book__price') # print(ret) # ret=Book.objects.filter(publish__name='北京出版社').values('name','price') # print(ret) # 查询北京出版社出版的价格大于19的书 # ret=Publish.objects.filter(name='北京出版社',book__price__gt=19).values('book__name','book__price') # print(ret)
# 多对多 # 查询红楼梦的所有作者名字 # ret=Book.objects.filter(name='红楼梦').values('authors__name') # print(ret) # ret=Author.objects.filter(book__name='红楼梦').values('name') # print(ret) # 查询图书价格大于30的所有作者名字 # ret=Book.objects.filter(price__gt=30).values('authors__name') # print(ret)
# 进阶练习--连续跨表 # 查询北京出版社出版过的所有书籍的名字以及作者的姓名 # ret=Publish.objects.filter(name='北京出版社').values('book__name','book__authors__name') # print(ret) # ret=Book.objects.filter(publish__name='北京出版社').values('name','authors__name') # print(ret) # 手机号以151开头的作者出版过的所有书籍名称以及出版社名称 # ret=AuthorDetail.objects.filter(phone__startswith='13').values('author__book__name','author__book__publish__name') # print(ret) # ret=Book.objects.filter(authors__authordetail__phone__startswith='13').values('name','publish__name') # print(ret)

五 聚合查询和分组查询

from django.db.models import Avg,Count,Max,Min,Sum
  
#聚合查询aggregate() # 计算所有图书的平均价格 # ret=Book.objects.all().aggregate(Avg('price')) # print(ret)
# 计算图书的最高价格 # ret=Book.objects.all().aggregate(Max('price')) # print(ret)
#aggregate是queryset的终止子句
# 计算图书的最高价格,最低价格,平均价格,总价 # ret=Book.objects.all().aggregate(Max('price'),Min('price'),Avg('price'),Sum('price')) # print(ret) #分组查询annotate() # 统计每一本书作者个数 # ret=Book.objects.all().annotate(c=Count('authors')) # print(ret) # for r in ret: # print(r.name,'---->',r.c) # ret=Book.objects.all().annotate(c=Count('authors')).values('name','c') # print(ret)
# 统计每一个出版社的最便宜的书(以谁group by 就以谁为基表) # ret=Publish.objects.all().annotate(m=Min('book__price')).values('name','m') # print(ret)
# 统计每一本以py开头的书籍的作者个数 # ret1=Book.objects.all().filter(name__startswith='py').annotate(c=Count('authors')).values('name','c') # print(ret1)
# 总结: group by 谁,就以谁做基表,filter过滤,annotate取分组,values取值
# 总结终极版本 # values在前,表示group by 在后,表示取值 # filter在前,表示where条件,在后表示having
# 统计每一本以py开头的书籍的作者个数--套用模板 # ret2=Book.objects.all().values('name').filter(name__startswith='py').annotate(c=Count('authors')).values('name','c') # print(ret2)
# 查询各个作者出的书的总价格 # ret=Author.objects.all().values('name').annotate(s=Sum('book__price')).values('name','s') # ret=Author.objects.all().annotate(s=Sum('book__price')).values('name','s') # print(ret)
#查询名字叫lqz作者书的总价格 # ret=Author.objects.all().values('pk').filter(name='lqz').annotate(s=Sum('book__price')).values('name','s') # print(ret)
# 查询所有作者写的书的总价格大于30 # ret=Author.objects.all().values('pk').annotate(s=Sum('book__price')).filter(s__gt=2).values('name','s') # ret=Author.objects.all().annotate(s=Sum('book__price')).filter(s__gt=30).values('name','s') # print(ret)
# 总结终极版本 # values在前,表示group by 在后,表示取值 # filter在前,表示where条件,在后表示having
# 统计不止一个作者的图书 ret=Book.objects.all().values('pk').annotate(c=Count('authors')).filter(c__gt=1).values('name','c') # ret = Book.objects.annotate(author_num=Count("authors")).filter(author_num__gt=1).values('name','author_num') print(ret)

六 F查询和Q查询

   
   # F函数
   from
django.db.models import F # 查询评论数大于阅读数的书 # 这样不行,进行不下去了 # ret=Book.objects.all().filter(commit_num__gt=reat_num) # 这么来做 # ret=Book.objects.all().filter(commit_num__gt=F('reat_num')) # print(ret) # 把所有书的评论数加1 # 不行,进行不下去 # ret=Book.objects.all().update(commit_num+=1) # 不行,进行不下去 # ret=Book.objects.all().update(commit_num=commit_num+1) # 这样来做 # ret=Book.objects.all().update(commit_num=F('commit_num')+1) # print(ret) # 把python这本书的阅读数减5 # ret = Book.objects.all().filter(name='python').update(reat_num=F('reat_num') - 5) # print(ret) # Q函数 为了表示与& ,或 | ,非 ~, from django.db.models import Q
# 查询作者名字是lqz或者名字是egon的书 # 这样行不通 # ret=Book.objects.all().filter(authors__name='lqz',authors__name='egon') # 这样出来 # ret=Book.objects.all().filter(Q(authors__name='lqz')|Q(authors__name='egon')) # print(ret) # 没有意义 # ret = Book.objects.all().filter(Q(authors__name='lqz') & Q(authors__name='egon')) # print(ret)
# 查询作者不是lqz的书 # ret=Book.objects.filter(~Q(authors__name='lqz')) # print(ret)    # 构建很复杂的逻辑,需要用括号来区分    # ret = Book.objects.filter((Q(name='红楼梦') & Q(price__gt=100)) | Q(pk__gt=2))    # print(ret)

猜你喜欢

转载自www.cnblogs.com/liweiwei0307/p/9960430.html