多表关联创建增删改查,一对一,一对多,多对多

创建表

from django.db import models

# Create your models here.

#作者表
class Author(models.Model): #比较常用的信息放到这个表里面

    name=models.CharField( max_length=32)
    age=models.IntegerField()
    # 与AuthorDetail建立一对一的关系,一对一的这个关系字段写在两个表的任意一个表里面都可以
    authorDetail=models.OneToOneField(to="AuthorDetail",to_field="id",on_delete=models.CASCADE) #就是foreignkey+unique,只不过不需要我们自己来写参数了,并且orm会自动帮你给这个字段名字拼上一个_id,数据库中字段名称为authorDetail_id

    def __str__(self):
        return self.name

#作者详细信息表
class AuthorDetail(models.Model):#不常用的放到这个表里面
    birthday=models.DateField()
    telephone=models.CharField(max_length=32)
    addr=models.CharField( max_length=64)

    def __str__(self):
        return self.telephone

#出版社表 和 书籍表 一对多的关系
class Publish(models.Model):
    name=models.CharField( max_length=32)
    city=models.CharField( max_length=32)
    email=models.EmailField() #charField类似,EmailField做邮箱数据校验使用

    def __str__(self):
        return self.name

#多对多的表关系,我们学mysql的时候是怎么建立的,是不是手动创建一个第三张表,然后写上两个字段,每个字段外键关联到另外两张多对多关系的表,orm的manytomany自动帮我们创建第三张表,两种方式建立关系都可以,以后的学习我们暂时用orm自动创建的第三张表,因为手动创建的第三张表我们进行orm操作的时候,很多关于多对多关系的表之间的orm语句方法无法使用
#如果你想删除某张表,你只需要将这个表注销掉,然后执行那两个数据库同步指令就可以了,自动就删除了。

#书籍表
class Book(models.Model):

    nid = models.AutoField(primary_key=True)
    title = models.CharField( max_length=32)
    publishDate=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2)#Decimal ,max_digits整数加小数位数,decimal_places小数位数

    # 与Publish建立一对多的关系,外键字段建立在多的一方,字段publish如果是外键字段,那么它自动是int类型
    publishs=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)
    #foreignkey里面可以加很多的参数,都是需要咱们学习的,慢慢来,to指向表,to_field指向你关联的字段,不写这个,默认会自动关联主键字段,on_delete级联删除字段名称不需要写成publish_id,orm在翻译foreignkey的时候会自动给你这个字段拼上一个_id,这个字段名称在数据库里面就自动变成了publish_id
    # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表,并且注意一点,你查看book表的时候,你看不到这个字段,因为这个字段就是创建第三张表的意思,不是创建字段的意思,所以只能说这个book类里面有authors这个字段属性
    authors=models.ManyToManyField(to='Author',) #注意不管是一对多还是多对多,写to这个参数的时候,最后后面的值是个字符串,不然你就需要将你要关联的那个表放到这个表的上面

    def __str__(self):
        return self.title

增删改操作:

    #增删改查
        #1增
            #1.1一对一增加
    '''
    #作者信息表
    author_detail = models.AuthorDetail.objects.create(
        birthday='2000-01-13',
        telephone='15265891211',
        addr='上海浦东新区',
    )

    #作者表
    # 方式1:直接使用authorDetail使用对象来创建

    models.Author.objects.create(
        name='李白',
        age='56',
        authorDetail=author_detail,
    )

    # 方式2:使用数据库字段名称来创建
    models.Author.objects.create(
        name='苏轼',
        age='47',
        authorDetail_id=author_detail.id,
    )
   '''
    '''
        #1.2一对多
    #方式1:使用对象
    models.Book.objects.create(
        title = '钢铁怎样炼成',
        publishDate='2019-03-26',
        price = 17.8,
        publishs=models.Publish.objects.filter(id=2).first(),
        # publishs=models.Publish.objects.get(id=2),
    )

    #方式2:使用属性字段
    models.Book.objects.create(
        title = '木棒怎样炼成',
        publishDate='2017-03-26',
        price = 27.8,
        publishs_id=models.Publish.objects.get(id=2).id
    )
    '''

    #多对多
        #方式1:创建一个找到一个book对象,就可以调book表中的authors属性来添加对应的作者id,注意这儿使用add方法
    '''
    book_obj = models.Book.objects.get(nid=8)
    book_obj.authors.add(*[1,4])
    '''
        #方式2:使用对象 (不推荐使用)
    '''
    AUTHOR1=models.Author.objects.get(id=3)
    AUTHOR2 = models.Author.objects.get(id=4)
    AUTHOR3 = models.Author.objects.get(id=1)
    book_obj1 = models.Book.objects.get(nid=7)
    book_obj1.authors.add(*[AUTHOR1,AUTHOR2,AUTHOR3])
    '''


    #删除 一对一,多对多的删除和单表删除是一样的
    '''
    # 一对一 、一对多。删除被依赖的依赖的也被删除。删除依赖被依赖的不会删除
    models.AuthorDetail.objects.get(id=2).delete()

    #多对多删除
    #找到nid为6的书籍,
    book_obj = models.Book.objects.get(nid=6)
    #删除作者id为6的数据
    book_obj.authors.remove(6)
    #删除多个
    book_obj.authors.remove(*[6,5])
    #删除作者id为6的所有数据
    book_obj.authors.clear()
    #删除所有作者id为6的数据,并添加绑定一条id为1的数据
    book_obj.authors.set("1")
    #绑定一条id为1和5的两条数据,注意这儿不用打散
    book_obj.authors.set(["1","5"])
    '''

    #更新 找到bookid为5,更新绑定信息
    '''
    #一对一
    models.Author.objects.filter(id=5).update(
        name = '礼拜',
        age=17,
        # 根据对象
        # authorDetail = models.AuthorDetail.objects.get(id=5),
        # 根据id更新
        authorDetail_id = 4,
    )
    #一对多
    models.Book.objects.filter(nid=4).update(
        title = '钢铁怎么练成',
        # publishs =  models.Publish.objects.get(id=3)
        publishs_id = 3,
    )
    '''

 基于对象的跨表查询 --- 类似于子查询

正向or反向查询:关系属性(字段)写在那个类(表)里面,从当前类的数据去查询它关联类(表)的数据,反之交反向查询。

  

    #查询
    """
    #一对一
        #正向查询 靠关联的属性字段查询
        #查询罗贯中地址是什么
    author_obj = models.Author.objects.filter(name="罗贯中").first()
    # author_obj.authorDetail 拿到一对一关联的对象,我们就可以通过属性来获取值
    print(author_obj.authorDetail.addr) #北京

        #反向查询 根据小写的类名查询
        # 查询一下15235412112电话是什么人
    author_detail_obj = models.AuthorDetail.objects.get(telephone="15235412112")
    # author_detail_obj.author 拿到一对一的关联对象,可以通过属性来获取
    print(author_detail_obj.author.name) #李白

    '''
                正向查询: Authorobj.authorDetail,对象.关联属性名称
        Author------------------------------------>AuthorDetail
              <------------------------------------
                反向查询:AuthorDetailobj.author,对象.类名小写.属性名
    '''
    """
    #一对多
    """
   # 查询西游记出版社是什么
    #正向查询
    #查询书名为西游记的对象,调用关联对象,在获取属性
    book_obj = models.Book.objects.get(title="西游记")
    print(book_obj.publishs.name)

    # 反向查询
    #查询新华出版社出版了那些书
    publish_obj = models.Publish.objects.get(name='新华出版社')
    print(publish_obj.book_set.all())  #<QuerySet [<Book: 水浒传>]>
    
    '''
                正向查询 book_obj.publishs.属性
        Book-------------------------------------------------->Publish
            <--------------------------------------------------
                反向查询 publish_obj.book_set.all()  对象.表名小写_set
    
    '''
    """
    #多对多
    """
    #西游记是谁写的
    #正向查询
    book_obj = models.Book.objects.get(title='西游记')
    print(book_obj.authors.all()) #<QuerySet [<Author: 罗贯中>, <Author: 吴承恩>]>

    #查询吴承恩写了那些书
    author_obj = models.Author.objects.get(name='吴承恩')
    print(author_obj.book_set.all()) #<QuerySet [<Book: 西游记>, <Book: 水浒传>, <Book: 钢铁怎样炼成>]>

    '''
            正向查询 book_obj.表明小写.all()
        Book-------------------------------------->Author
            <--------------------------------------
            反向查询 author_obj.表名小写_set.all()
    '''
    """

基于双下划线的跨表查询 --- 连标 join

    # 基于双下划线的跨表查询 -- 连标join

    #一对一
    '''
        #1.查询罗贯中地址是什么
    #方式1 正向查询
    addr1 = models.Author.objects.filter(name='罗贯中').values()
    print(addr1) #<QuerySet [{'id': 1, 'name': '罗贯中', 'age': 36, 'authorDetail_id': 1}]>
    addr = models.Author.objects.filter(name='罗贯中').values("authorDetail__addr",'name').first() #{'authorDetail__addr': '北京', 'name': '罗贯中'}
    print(addr) #<QuerySet [{'authorDetail__addr': '北京', 'name': '罗贯中'}]>
    #方式2 反向查询
    obj = models.AuthorDetail.objects.filter(author__name='罗贯中').values('addr','author__age') #<QuerySet [{'addr': '北京', 'author__age': 36}]>
    print(obj)

        #电话号码13854712314是谁
    #方式1 正向查询
    name_obj1 = models.AuthorDetail.objects.filter(telephone='13854712314').values('author__name') #<QuerySet [{'author__name': '吴承恩'}]>
    print(name_obj1)

    #方式2 反向查询
    name_obj2 = models.Author.objects.filter(authorDetail__telephone='13854712314').values('name') #<QuerySet [{'name': '吴承恩'}]>
    print(name_obj2)
    '''

    #一对多
    '''
        # 查询西游记出版社是什么
    # 方式1 正向查询
    obj = models.Book.objects.filter(title='西游记').values('publishs__name') #<QuerySet [{'publishs__name': 'Cc出版社'}]>
    print(obj)

    # 方式2 反向查询
    obj1 = models.Publish.objects.filter(book__title='西游记').values('name') #<QuerySet [{'publishs__name': 'Cc出版社'}]>
    print(obj)

        #西安出版社出版了那些书
    obj2 = models.Publish.objects.filter(name='西安出版社').values('book__title') #<QuerySet [{'book__title': '三国演义'}, {'book__title': '钢铁怎样炼成'}, {'book__title': '木棒怎样炼成'}]>
    print(obj2)

    obj3 = models.Book.objects.filter(publishs__name='西安出版社').values('title') #<QuerySet [{'title': '三国演义'}, {'title': '钢铁怎样炼成'}, {'title': '木棒怎样炼成'}]>
    print(obj3)

        #钢铁怎样炼成是谁写的
    obj4 = models.Book.objects.filter(title='钢铁怎样炼成').values('authors__name') #<QuerySet [{'authors__name': '罗贯中'}, {'authors__name': '吴承恩'}, {'authors__name': '李白'}]>
    print(obj4)

    obj5 = models.Author.objects.filter(book__title='钢铁怎样炼成').values('name') #<QuerySet [{'name': '罗贯中'}, {'name': '吴承恩'}, {'name': '李白'}]>
    print(obj5)

        #李白写了那些书
    obj6 = models.Author.objects.filter(name='李白').values('book__title') #<QuerySet [{'book__title': '红楼梦'}, {'book__title': '钢铁怎样炼成'}, {'book__title': '木棒怎样炼成'}]>
    print(obj6)

    obj7 = models.Book.objects.filter(authors__name='李白').values('title') #<QuerySet [{'title': '红楼梦'}, {'title': '钢铁怎样炼成'}, {'title': '木棒怎样炼成'}]>
    print(obj7)
    '''
    #进阶 三表关联
        #查询西安出版社出版的书的名称以及作者名称
    #正向查询
    obj8 = models.Publish.objects.filter(name='西安出版社').values('book__authors__name','book__title')
    print(obj8) #<QuerySet [{'book__authors__name': '罗贯中', 'book__title': '三国演义'}, {'book__authors__name': '罗贯中', 'book__title': '钢铁怎样炼成'}, {'book__authors__name': '罗贯中', 'book__title': '木棒怎样炼成'}, {'book__authors__name': '吴承恩', 'book__title': '钢铁怎样炼成'}, {'book__authors__name': '李白', 'book__title': '钢铁怎样炼成'}, {'book__authors__name': '李白', 'book__title': '木棒怎样炼成'}, {'book__authors__name': '苏轼', 'book__title': '三国演义'}]>
    #反向查询
    obj9 = models.Book.objects.filter(publishs__name='西安出版社').values('title','authors__name')
    print(obj9) #<QuerySet [{'title': '三国演义', 'authors__name': '罗贯中'}, {'title': '钢铁怎样炼成', 'authors__name': '罗贯中'}, {'title': '木棒怎样炼成', 'authors__name': '罗贯中'}, {'title': '钢铁怎样炼成', 'authors__name': '吴承恩'}, {'title': '钢铁怎样炼成', 'authors__name': '李白'}, {'title': '木棒怎样炼成', 'authors__name': '李白'}, {'title': '三国演义', 'authors__name': '苏轼'}]>

    obj10 = models.Author.objects.filter(book__publishs__name='西安出版社').values('name','book__title')
    print(obj10) #<QuerySet [{'name': '罗贯中', 'book__title': '三国演义'}, {'name': '罗贯中', 'book__title': '钢铁怎样炼成'}, {'name': '罗贯中', 'book__title': '木棒怎样炼成'}, {'name': '吴承恩', 'book__title': '钢铁怎样炼成'}, {'name': '李白', 'book__title': '钢铁怎样炼成'}, {'name': '李白', 'book__title': '木棒怎样炼成'}, {'name': '苏轼', 'book__title': '三国演义'}]>

    #进阶2
        #手机号以4结尾的作者,出版社过的所有书籍名称以及出版社名称
    obj11 = models.AuthorDetail.objects.filter(telephone__endswith='4').values('author__book__title','author__book__publishs__name')
    print(obj11) #<QuerySet [{'author__book__title': '水浒传', 'author__book__publishs__name': '新华出版社'}, {'author__book__title': '钢铁怎样炼成', 'author__book__publishs__name': '西安出版社'}, {'author__book__title': '西游记', 'author__book__publishs__name': 'Cc出版社'}]>
    obj12 = models.Book.objects.filter(authors__authorDetail__telephone__endswith='4').values('title','publishs__name')
    print(obj12) #<QuerySet [{'title': '西游记', 'publishs__name': 'Cc出版社'}, {'title': '水浒传', 'publishs__name': '新华出版社'}, {'title': '钢铁怎样炼成', 'publishs__name': '西安出版社'}]>

聚合查询、分组查询、F查询和Q查询

    #聚合
        #查询出所有图书的平均价格
    #首先查询出数据,然后调aggregate这个方法里面传对应聚合函数,一旦调用了aggregate方法就不能调用queryset的方法,因为它返回的是字典
    from django.db.models import Avg,Max,Min,Sum,Count
    avg_price = models.Book.objects.all().aggregate(Avg('price')) #{'price__avg': 30.883333} dict
    avg_price = models.Book.objects.all().aggregate(a=Avg('price')) #{'a': 30.883333} 可以给key起个别名 a
    print(avg_price)

 

    #分组查询 :首先在values里面写要分组的字段,分组完成使用分组函数annotate里面写聚会函数,注意如果values里面写了多个值,并且后面annotate,就是按照values里面的最后一个值分组
        # 查询每个出版社出版书的平均价格
    from django.db.models import Avg, Max, Min, Sum, Count

    #方式1:
    avg_price = models.Book.objects.values('publishs_id').annotate(a=Avg('price'))
    #SELECT `app01_book`.`publishs_id`, AVG(`app01_book`.`price`) AS `a` FROM `app01_book` GROUP BY `app01_book`.`publishs_id` ORDER BY NULL LIMIT 21
    # <QuerySet [{'publishs_id': 1, 'a': 53.2}, {'publishs_id': 2, 'a': 29.7}, {'publishs_id': 3, 'a': 21.5}]>
    print(avg_price)
    avg_price1 = models.Book.objects.values('publishs_id','nid').annotate(a=Avg('price'))
    print(avg_price1)
    #SELECT `app01_book`.`publishs_id`, `app01_book`.`nid`, AVG(`app01_book`.`price`) AS `a` FROM `app01_book` GROUP BY `app01_book`.`nid` ORDER BY NULL LIMIT 21;
    #<QuerySet [{'publishs_id': 3, 'nid': 1, 'a': 13.5}, {'publishs_id': 3, 'nid': 2, 'a': 29.5}, {'publishs_id': 1, 'nid': 3, 'a': 53.2}, {'publishs_id': 2, 'nid': 4, 'a': 43.5}, {'publishs_id': 2, 'nid': 7, 'a': 17.8}, {'publishs_id': 2, 'nid': 8, 'a': 27.8}]>

    #方式2:通过关联并且分组
    ret = models.Publish.objects.annotate(a = Avg('book__price'))#<QuerySet [<Publish: Cc出版社>, <Publish: 新华出版社>, <Publish: 西安出版社>]>
    print(ret.values()) #<QuerySet [{'id': 3, 'name': 'Cc出版社', 'city': '南京', 'email': 'cy@163.com', 'a': 21.5}, {'id': 1, 'name': '新华出版社', 'city': '上海', 'email': '352@163.com', 'a': 53.2}, {'id': 2, 'name': '西安出版社', 'city': '西安', 'email': 'xian@qq.com', 'a': 29.7}]>
    print(ret.values('name','a')) #<QuerySet [{'name': 'Cc出版社', 'a': 21.5}, {'name': '新华出版社', 'a': 53.2}, {'name': '西安出版社', 'a': 29.7}]>

    ret1 = models.Publish.objects.annotate(a = Avg('book__price')).values('name','a')
    print(ret1)

    #分组后过滤
    ret2 = models.Publish.objects.values('book__publishs_id').annotate(a= Avg('book__price')).values().filter(a__gt=22)
    print(ret2)

  F查询与Q查询

 

posted @ 2021-04-01 15:50  西西cc  阅读(751)  评论(0)    收藏  举报