9、多表模型建立,一對一,一對多,基於對像的多表模型等

環境:python

django1.9環境:
mysql

settings.py,註釋csrf,而且設置使用mysql數據庫
git

數據庫的對應關係圖:sql

圖片.png

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

圖片.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

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)
相關文章
相關標籤/搜索