环境:python
django1.9环境:
mysql
settings.py,注释csrf,而且设置使用mysql数据库
git
数据库的对应关系图:sql
1、多表模型建立,一对多增删改查,多对多增删改查数据库
一对多:
django
models.py
app
总结:ide
#用了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
2、添加表记录
在11-13数据库中的app01_publish表中添加出版社数据:
在项目的根下添加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表中就会出先以前插入的数据。
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) # 西游记
一对一修改数据:
方式一:
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
方式二:(为了测试,先把app01_book_authors表中的数据所有删除)
book=Book.objects.filter(name='红楼梦').first() book.authors.add(1,2)
多对多删除:
方式一:
# remove,能够传对象,能够传id,能够传多个,不要混着用
lqz=Author.objects.filter(name='lqz').first() book=Book.objects.filter(name='红楼梦').first() book.authors.remove(lqz)
方式二:
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()
多对多修改:
# set,先清空,在新增,要传一个列表,列表内能够是, id,也能够是对象
原来表中的数据:
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,])
修改以后:
错误方式:
********这样不行,由于它打散了传过去了,至关于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
3、基于对象的跨表查询,一对一,一对多,多对多查询
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
4、******基于对象的查询,是子查询也就是屡次查询)
*********************基于双下划线的查询***************
# 一对一
# 查询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}]>
5、基于双下划线的一对多查询
# 查询出版社为北京出版社出版的全部图书的名字,价格 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')}]>
6、基于双下划线的多对多查询
# 查询红楼梦的全部做者名字 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)
7、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) --------------------------------- <QuerySet [<Book: 红楼梦>]> # 把全部书的评论数加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) <QuerySet [<Book: 红楼梦>, <Book: 西游记>, <Book: py书大全>]> # 构建很复杂的逻辑,须要用括号来区分 ret = Book.objects.filter((Q(name='红楼梦') & Q(price__gt=100)) | Q(pk__gt=2)) print(ret) ------------------------------ <QuerySet [<Book: py书大全>]>
总结:
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 上课讲的敲一遍