环境:

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.name


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

python3 manage makemigrations
python3 manage migrate

二、添加表记录

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

图片.png

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

import os
if __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 os

if __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=2
book.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.authordetail
print(authordetail.phone)
---------------------------------
13513513561

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

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

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

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

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

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

book=Book.objects.filter(name='红楼梦').first()
pulish=book.publish
print(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)
--------------------
<QuerySet [<Book: 红楼梦>]>
# 统计一下条数
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对象,可以继续点
---------------------------------------------
<QuerySet [<Author: egon>]>

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

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

            # 查询lqz写的所有书

egon=Author.objects.filter(name='egon').first()
books=egon.book_set.all()
print(books)
------------------------------------------------------
<QuerySet [<Book: 红楼梦>]>

 # 连续跨表
 # 查询红楼梦这本书所有的作者的手机号

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)
------------------------------
<QuerySet [{'authordetail__phone': '13513513561'}]>

# 以authordetail作为基表

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

ret=AuthorDetail.objects.filter(author__name='egon').values('phone')
print(ret)
---------------------------------------------
<QuerySet [{'phone': '13513513561'}]>

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

ret=Author.objects.filter(name='egon').values('sex','authordetail__phone')
print(ret)
-------------------------
<QuerySet [{'sex': 1, 'authordetail__phone': '13513513561'}]>


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

ret=Author.objects.filter(authordetail__phone='13513513561').values('sex')
print(ret)
-------------------------------------
<QuerySet [{'sex': 1}]>
ret=AuthorDetail.objects.filter(phone='13513513561').values('author__sex')
print(ret)
-------------------------
<QuerySet [{'author__sex': 1}]>

五、基于双下划线的一对多查询

# 查询出版社为北京出版社出版的所有图书的名字,价格
ret=Publish.objects.filter(name='北京出版社').values('book__name','book__price')
print(ret)
----------------------------------------------------------------------
<QuerySet [{'book__name': '红楼梦', 'book__price': Decimal('34.50')}, {'book__name': '西游记', 'book__price': Decimal('553.30')}]>
------------------------------------------------------------------------
ret=Book.objects.filter(publish__name='北京出版社').values('name','price')
print(ret)
-----------------------------------------------------
<QuerySet [{'name': '红楼梦', 'price': Decimal('34.50')}, {'name': '西游记', 'price': Decimal('553.30')}]>

# 反向查询
# 查询北京出版社出版的价格大于19的书
ret=Publish.objects.filter(name='北京出版社',book__price__gt=19).values('book__name','book__price')
print(ret)
-----------------------------------------------------
<QuerySet [{'book__name': '红楼梦', 'book__price': Decimal('34.50')}, {'book__name': '西游记', 'book__price': Decimal('553.30')}]>

六、基于双下划线的多对多查询

# 查询红楼梦的所有作者名字
ret=Book.objects.filter(name='红楼梦').values('authors__name')
print(ret)
--------------------------
<QuerySet [{'book__name': '红楼梦', 'book__price': Decimal('34.50')}, {'book__name': '西游记', 'book__price': Decimal('553.30')}]>
-----------------------------------------------------------
ret=Author.objects.filter(book__name='红楼梦').values('name')
print(ret)
------------------------------------------------------------------
<QuerySet [{'name': 'egon'}]>
# 查询图书价格大于30的所有作者名字
ret=Book.objects.filter(price__gt=30).values('authors__name')
print(ret)
---------------------------------
<QuerySet [{'authors__name': 'egon'}, {'authors__name': None}]>
# 进阶练习--连续跨表

# 查询北京出版社出版过的所有书籍的名字以及作者的姓名
ret=Publish.objects.filter(name='北京出版社').values('book__name','book__authors__name')
print(ret)
----------------------------------------
<QuerySet [{'book__name': '红楼梦', 'book__authors__name': 'egon'}, {'book__name': '西游记', 'book__authors__name': None}]>
----------------------------------------------------------
ret=Book.objects.filter(publish__name='北京出版社').values('name','authors__name')
print(ret)
---------------------------------------
<QuerySet [{'name': '红楼梦', 'authors__name': 'egon'}, {'name': '西游记', 'authors__name': None}]>

# 手机号以135开头的作者出版过的所有书籍名称以及出版社名称
ret=AuthorDetail.objects.filter(phone__startswith='135').values('author__book__name','author__book__publish__name')
print(ret)
--------------------------------------------------
<QuerySet [{'author__book__name': '红楼梦', 'author__book__publish__name': '北京出版社'}]>
---------------------------------------------------------------------
ret=Book.objects.filter(authors__authordetail__phone__startswith='135').values('name','publish__name')
print(ret)
-----------------------------------------------------------------------
<QuerySet [{'name': '红楼梦', 'publish__name': '北京出版社'}]>

# 聚合查询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)
----------------------------------------------
<QuerySet [<Book: 红楼梦>, <Book: 西游记>]>
红楼梦 ----> 1
西游记 ----> 0
---------------------------------------------
ret=Book.objects.all().annotate(c=Count('authors')).values('name','c')
print(ret)
------------------------------------
<QuerySet [{'name': '红楼梦', 'c': 1}, {'name': '西游记', 'c': 0}]>

# 统计每一个出版社的最便宜的书(以谁group by 就以谁为基表)
ret=Publish.objects.all().annotate(m=Min('book__price')).values('name','m')
print(ret)
------------------------------------------
<QuerySet [{'name': '北京出版社', 'm': Decimal('34.50')}]>
# 统计每一本以py开头的书籍的作者个数
ret=Book.objects.all().filter(name__startswith='py').annotate(c=Count('authors')).values('name','c')
print(ret)
--------------------------------
<QuerySet [{'name': 'py书大全', 'c': 0}]>

    # 总结:  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)
-----------------------------------
<QuerySet [{'name': 'py书大全', 'c': 0}]>

# 查询各个作者出的书的总价格
ret=Author.objects.all().values('name').annotate(s=Sum('book__price')).values('name','s')
print(ret)
--------------------------------------------------------
<QuerySet [{'name': 'egon', 's': Decimal('34.50')}]>

ret=Author.objects.all().annotate(s=Sum('book__price')).values('name','s')
print(ret)
----------------------------------------------------------
<QuerySet [{'name': 'egon', 's': Decimal('34.50')}]>

# 查询名字叫egon作者书的总价格
ret=Author.objects.all().values('pk').filter(name='egon').annotate(s=Sum('book__price')).values('name','s')
print(ret)
-----------------------------------
<QuerySet [{'name': 'egon', 's': Decimal('34.50')}]>

# 查询所有作者写的书的总价格大于30
ret=Author.objects.all().values('pk').annotate(s=Sum('book__price')).filter(s__gt=2).values('name','s')
print(ret)
-----------------------------------------
<QuerySet [{'name': 'egon', 's': Decimal('34.50')}]>

ret=Author.objects.all().annotate(s=Sum('book__price')).filter(s__gt=30).values('name','s')
print(ret)
-------------------------------------------
<QuerySet [{'name': 'egon', 's': Decimal('34.50')}]>

# 总结终极版本
# 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)