环境:

django1.9环境:

settings.py,注释csrf,并且设置使用mysql数据库

数据库的对应关系图:

图片.png

一、多表模型创建,一对多增删改查,多对多增删改查

一对多:

models.py

总结:

#用了OneToOneField和ForeignKey,模型表的字段,后面会自定加_id

# ManyToManyField会自动创建第三张表
# *************重点
# 一对一的关系:OneToOneField
# 一对多的关系:ForeignKey
# 多对多的关系:ManyToManyField

# id如果不写,会自动生成,名字叫nid,并且自增(数据库类型不同,生成的名字也会随之不同)

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=64)    email = models.EmailField()class AuthorDetail(models.Model):    id = models.AutoField(primary_key=True)    phone = models.CharField(max_length=32)    addr = models.CharField(max_length=64)class Author(models.Model):    id = models.AutoField(primary_key=True)    name = models.CharField(max_length=16)    # 数字类型    sex = models.IntegerField()    # # to='AuthorDetail'  加引号,这个表能找到就可以,不用引号,类必须在上面定义    authordetail = models.OneToOneField(to='AuthorDetail', to_field='id')    def __str__(self):        return self.nameclass 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

python3 manage makemigrations

python3 manage migrate

二、添加表记录

在11-13数据库中的app01_publish表中添加出版社数据:

图片.png

在项目的根下添加test.py文件

import osif __name__ == '__main__':    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pro11_13.settings")    import django    django.setup()    from app01.models import *     # 以上代码是属于如何让py文件在django环境中运行     # 一对多新增数据    # 添加一本北京出版社出版的书    # 第一种方式    ret=Book.objects.create(name='红楼梦',price=34.5,publish_id=1)    print(ret.name)     # 红楼梦

然后在book表中就会出先之前插入的数据。

图片.png

import osif __name__ == '__main__':    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pro11_13.settings")    import django    django.setup()    from app01.models import *    # 第二种方式,存对象publish=出版社的对象,存到数据库,是一个id    publish=Publish.objects.filter(pk=2).first()    ret = Book.objects.create(name='西游记', price=34.5, publish=publish)    print(ret.name)    # 西游记

图片.png

一对一修改数据:

方式一:

book=Book.objects.get(pk=1)book.publish=出版社对象book.publish_id=2book.save()

方式二:

book=Book.objects.filter(pk=1).update(publish=出版社对象)# book=Book.objects.filter(pk=1).update(publish_id=1)

多对多新增:

首先在数据中添加作者与作者详情

图片.png图片.png

# 为红楼梦这本书新增一个叫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

图片.png

方式二:(为了测试,先把app01_book_authors表中的数据全部删除)

book=Book.objects.filter(name='红楼梦').first()book.authors.add(1,2)

图片.png

多对多删除:

方式一:

# remove,可以传对象,可以传id,可以传多个,不要混着用

lqz=Author.objects.filter(name='lqz').first()book=Book.objects.filter(name='红楼梦').first()book.authors.remove(lqz)

图片.png

方式二:

lqz=Author.objects.filter(name='lqz').first()egon=Author.objects.filter(name='egon').first()book=Book.objects.filter(name='红楼梦').first()book.authors.remove(1)# book.authors.remove(1,2)# clear清空所有# book.authors.clear()

图片.png

多对多修改:

#  set,先清空,在新增,要传一个列表,列表内可以是, id,也可以是对象

原来表中的数据:

图片.png

lqz=Author.objects.filter(name='lqz').first()egon=Author.objects.filter(name='egon').first()book=Book.objects.filter(name='红楼梦').first()book.authors.set([2,])# 或者:# book.authors.set([lqz,])

修改之后:

图片.png

错误方式:

********这样不行,因为它打散了传过去了,相当于book.authors.set(lqz)# book.authors.set(*[lqz,])

总结:

添加表记录

        1 一对多新增
            -两种方式:
                -publish=对象
                -publish_id=id
        2 一对多删除:同单表删除
        3 一对多修改:两种方式,可以传对象,可以传id
        4 一对一跟一对多一样
        5 多对多:
            -add  ----->可以传对象,可以传id,可以传多个
            -remove  ----->可以传对象,可以传id,可以传多个
            -clear  ---->没有参数
            -set   ----->跟上面不一样,必须传列表,列表里面可以是对象,可以是id

三、基于对象的跨表查询,一对一,一对多,多对多查询

        1 一对一

            正向:正向查询按字段,(author---关联字段在author--->authordetail   ------>  按字段)

             # 查询egon作者的手机号   正向查询

author=Author.objects.filter(name='egon').first()authordetail=author.authordetailprint(authordetail.phone)---------------------------------13513513561

            反向:反向查询按表名小写,(authordetail------关联字段在author--->author  -----> 按表名小写)

            #  查询地址是 :山东 的作者名字   反向查询

authordetail=AuthorDetail.objects.filter(addr=' 上海').first()author = authordetail.authorprint(author.name)----------------------------egon

        2 一对多

            正向:正向查询按字段。(拿书查出版社信息)

            正向   book---关联字段在book--->publish   ------>  按字段

            正向 查询红楼梦这本书的出版社邮箱

book=Book.objects.filter(name='红楼梦').first()pulish=book.publishprint(pulish.email)-------------------564@qq.com

            反向:反向按表名小写_set.all()

            反向   publish------关联字段在book--->book  -----> 按表名小写_set.all()(拿出版社信息查询图书)。

            反向  查询地址是北京 的出版社出版的图书

publish=Publish.objects.filter(addr='北京').first()books=publish.book_set.all()  # publish.book_set.all()  拿出所有的图书print(books)--------------------
]># 统计一下条数books=publish.book_set.all().count()print(books)-----------------1

        3 多对多

            正向:正向查询按字段

            正向   book---关联字段在book--->author   ------>  按字段.all()

            #查询红楼梦这本书所有的作者

book=Book.objects.filter(name='红楼梦').first()print(book.authors.all())   # 是所有的作者,是一个queryset对象,可以继续点---------------------------------------------
]>

            反向查询:反向按表名小写_set.all()

            反向   author------关联字段在book--->book  -----> 按表名小写_set.all()

            # 查询lqz写的所有书

egon=Author.objects.filter(name='egon').first()books=egon.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)-----------------------------------------13513513561

四、******基于对象的查询,是子查询也就是多次查询)

*********************基于双下划线的查询***************

# 一对一

# 查询lqz作者的手机号   正向查询  跨表的话,按字段
# 以author表作为基表

ret=Author.objects.filter(name='egon').values('authordetail__phone')print(ret)------------------------------

# 以authordetail作为基表

# 反向查询,按表名小写  跨表的话,用表名小写

ret=AuthorDetail.objects.filter(author__name='egon').values('phone')print(ret)---------------------------------------------

# 查询lqz这个作者的性别和手机号

# 正向

ret=Author.objects.filter(name='egon').values('sex','authordetail__phone')print(ret)-------------------------

# 查询手机号是13513513561的作者性别

ret=Author.objects.filter(authordetail__phone='13513513561').values('sex')print(ret)-------------------------------------
ret=AuthorDetail.objects.filter(phone='13513513561').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)---------------------------------------
# 手机号以135开头的作者出版过的所有书籍名称以及出版社名称ret=AuthorDetail.objects.filter(phone__startswith='135').values('author__book__name','author__book__publish__name')print(ret)--------------------------------------------------
---------------------------------------------------------------------ret=Book.objects.filter(authors__authordetail__phone__startswith='135').values('name','publish__name')print(ret)-----------------------------------------------------------------------

# 聚合查询aggregate

from django.db.models import Avg,Count,Max,Min,Sum# 计算所有图书的平均价格ret=Book.objects.all().aggregate(Avg('price'))print(ret)-----------------------{'price__avg': 293.9}#  计算图书的最高价格ret=Book.objects.all().aggregate(Max('price'))print(ret)------------------------------------{'price__max': Decimal('553.30')}#他是queryset的终止子句# 计算图书的最高价格,最低价格,平均价格,总价ret=Book.objects.all().aggregate(Max('price'),Min('price'),Avg('price'),Sum('price'))print(ret)---------------------------------------------{'price__max': Decimal('553.30'), 'price__min': Decimal('34.50'), 'price__avg': 293.9, 'price__sum': Decimal('587.80')}# 分组查询annotate()# 统计每一本书作者个数ret=Book.objects.all().annotate(c=Count('authors'))print(ret)for r in ret:    print(r.name,'---->',r.c)----------------------------------------------
]>红楼梦 ----> 1西游记 ----> 0---------------------------------------------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开头的书籍的作者个数ret=Book.objects.all().filter(name__startswith='py').annotate(c=Count('authors')).values('name','c')print(ret)--------------------------------
    # 总结:  group by 谁,就以谁做基表,filter过滤,annotate取分组,values取值    # 总结终极版本    # values在前,表示group by 在后,表示取值    # filter在前,表示where条件,在后表示having    # 统计每一本以py开头的书籍的作者个数--套用模板ret=Book.objects.all().values('name').filter(name__startswith='py').annotate(c=Count('authors')).values('name','c')print(ret)-----------------------------------
# 查询各个作者出的书的总价格ret=Author.objects.all().values('name').annotate(s=Sum('book__price')).values('name','s')print(ret)--------------------------------------------------------
ret=Author.objects.all().annotate(s=Sum('book__price')).values('name','s')print(ret)----------------------------------------------------------
# 查询名字叫egon作者书的总价格ret=Author.objects.all().values('pk').filter(name='egon').annotate(s=Sum('book__price')).values('name','s')print(ret)-----------------------------------
# 查询所有作者写的书的总价格大于30ret=Author.objects.all().values('pk').annotate(s=Sum('book__price')).filter(s__gt=2).values('name','s')print(ret)-----------------------------------------
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.annotate(author_num=Count("authors")).filter(author_num__gt=1).values('name','author_num')ret=Book.objects.all().values('pk').annotate(c=Count('authors')).filter(c__gt=1).values('name','c')print(ret)