环境:

django1.9环境:

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

数据库的对应关系图:

九、多表模型创建,一对一,一对多,基于对像的多表模型等_第1张图片

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

一对多:

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表中添加出版社数据:

九、多表模型创建,一对一,一对多,基于对像的多表模型等_第2张图片

在项目的根下添加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表中就会出先之前插入的数据。

九、多表模型创建,一对一,一对多,基于对像的多表模型等_第3张图片


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)
    # 西游记

九、多表模型创建,一对一,一对多,基于对像的多表模型等_第4张图片

一对一修改数据:

方式一:

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)

多对多新增:

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

九、多表模型创建,一对一,一对多,基于对像的多表模型等_第5张图片九、多表模型创建,一对一,一对多,基于对像的多表模型等_第6张图片

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

九、多表模型创建,一对一,一对多,基于对像的多表模型等_第7张图片

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

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

九、多表模型创建,一对一,一对多,基于对像的多表模型等_第8张图片

多对多删除:

方式一:

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

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

九、多表模型创建,一对一,一对多,基于对像的多表模型等_第9张图片

方式二:

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

九、多表模型创建,一对一,一对多,基于对像的多表模型等_第10张图片

多对多修改:

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

原来表中的数据:

九、多表模型创建,一对一,一对多,基于对像的多表模型等_第11张图片

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,])

修改之后:

九、多表模型创建,一对一,一对多,基于对像的多表模型等_第12张图片

错误方式:

********这样不行,因为它打散了传过去了,相当于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)
-------------------
[email protected]


            反向:反向按表名小写_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)
-----------------------------------


# 查询所有作者写的书的总价格大于30
ret=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)

七、F函数

models.py

from django.db import models


# Create your models here.

#用了OneToOneField和ForeignKey,模型表的字段,后面会自定加_id
# ManyToManyField会自动创建第三张表
# *************重点
# 一对一的关系:OneToOneField
# 一对多的关系:ForeignKey
# 多对多的关系:ManyToManyField


class Publish(models.Model):
    # id如果不写,会自动生成,名字叫nid,并且自增
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)
    email = models.EmailField()


class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    # 数字类型
    sex = models.IntegerField()
    # 可以用ForeignKey,但是得设置唯一性约束,会报警告,不建议用,建议用OneToOneField
    # authordetail=models.ForeignKey(unique=True)
    # to='AuthorDetail'  加引号,这个表能找到就可以,不用引号,类必须在上面定义
    authordetail = models.OneToOneField(to='AuthorDetail', to_field='id')

    def __str__(self):
        return self.name


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,db_index=True)
    price = models.DecimalField(max_digits=5, decimal_places=2)

    # 阅读数
    reat_num=models.IntegerField(default=0)
    # 评论数
    commit_num=models.IntegerField(default=0)
    publish = models.ForeignKey(to=Publish, to_field='id',on_delete=models.CASCADE)

    authors = models.ManyToManyField(to=Author)


    # test=models.PositiveSmallIntegerField()
    def __str__(self):
        return self.name


class Test(models.Model):
    name=models.CharField(max_length=32)
    class Meta:
        db_table='aaa'

python3 manage makemigrations
python3 manage migrate

import os

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

    django.setup()

    from app01.models import *
from django.db.models import F
# 查询评论数大于阅读数的书
ret=Book.objects.all().filter(commit_num__gt=F('reat_num'))
print(ret)
---------------------------------
]>

# 把所有书的评论数加100
ret=Book.objects.all().update(commit_num=F("commit_num")+100)
print(ret)

# 把红楼梦这本书的阅读数减5
ret = Book.objects.all().filter(name='红楼梦').update(reat_num=F('reat_num') - 5)
print(ret)

# Q函数 为了表示与& ,或 | ,非 ~,
from django.db.models import Q
# 查询作者不是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)
------------------------------
]>

总结:

1基于双下划线的跨表查询
		套路一样,用__跨表
		-一对多
		-多对多
	2 聚合查询
		-聚合函数
		    from django.db.models import Avg,Count,Max,Min,Sum
			# 计算所有图书的平均价格
			# ret=Book.objects.all().aggregate(Avg('price'))
			# print(ret)
		
	
	3分组查询
		终极总结:
			values在前,表示group by,在后,表示取值
			filter在前,表示过滤(where),在后,表示having(对分组之后的结果再进行过滤)
	4 F查询与Q查询

		-F为了字段=后面的值,不能放字段,所以用F函数包裹一下就可以了
		-Q为了构造与&,或|,非~的关系
		
	5 常用字段:必须记住,非常用字段,了解即可
	6 orm字段参数:
		-null  可以为空
		-unique  唯一性约束
		-default 默认值
		-db_index 为该字段建索引
		-只给日期类型和时间类型用
			-auto_now_add    新增数据时,默认把当前时间存入
			-auto_now        修改的时候,默认把当前时间存入
	7 关系字段
		ForeignKey
			-to  关联哪个表
			-to_field 关联的字段
			-related_name 反向操作时,使用的字段名,用于代替原反向查询时的'表名_set'。(一般不要用)
			-related_query_name :基于双下划线的反向查询之前按表名小写(一般不要用)
			-on_delete:models.CASCADE,models.SET_NULL
			-db_constraint:db_constraint=False代表,不做外键关联


			
作业:
	1 手动创建第三张表,并且新增,删除,查询数据
	2 整理博客
	3 上课讲的敲一遍