環境: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,而且自增(數據庫類型不一樣,生成的名字也會隨之不一樣)spa
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)