Django從入門到放棄二 -- ORM之單表查詢與多表查詢

 

一、ORM -- 數據庫交互

  參考地址:

http://www.cnblogs.com/yuanchenqi/articles/8933283.html

https://www.cnblogs.com/liuqingzheng/p/9506212.html

  SQL中的表與ORM直觀對比圖:ORM在python中是以類的方式定義的,在執行python時,類會轉換成對應的SQL語句。

  1.1、首先學習,在Python中創建數據庫

     1.1.1).首先在DB裏面創建庫:create database book_orm;

     1.1.2).在Django項目裏面,設置settings.py文件

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME':'sudada',   # 要連接的數據庫,連接前需要創建好
        'USER':'sudada',   # 連接數據庫的用戶名
        'PASSWORD':'123456',   # 連接數據庫的密碼
        'HOST':'127.0.0.1',    # 連接主機,默認本級
        'PORT':3306            # 端口 默認3306
    }
}

# 手動創建數據庫
  create DATABASE `sudada` default charset utf8;
# 備註: 制定utf8字符集

 

    1.1.3).在Django項目裏面,設置models.py文件 (數據表結構)

class Book(models.Model):                       # Book可以理解爲要創建的表名(實際創建時會附帶上Django應用的名稱)
    id = models.AutoField(primary_key=True)     # 主鍵:主鍵字段不可修改,如果你給某個對象的主鍵賦個新值實際上是創建一個新對象,並不會修改原來的對象。
    title = models.CharField(max_length=32)     # CharField用來存字符串的,對應varchar
    pub_date = models.DateField()               # 存日期的
    price = models.DecimalField(max_digits=8, decimal_places=2) # 存價格的
    publish = models.CharField(max_length=32)   # CharField用來存字符串的,對應varchar

 

     1.1.4).在windows命令行使用:python3 manage.py makemigrations 命令(生成一條記錄,並沒有提交到數據庫)  創建表:(步驟一)

    1.1.4.1) 這一步會報錯,如下:這是由於使用了MySQL模塊導致的,在python3中,一般都是使用pymysql的,那麼我們就需要告訴Django要使用pymysql。

   1.1.4.2) 在app01目錄下的__init__.py文件中或者在項目目錄下的__init__.py文件中定義如下代碼:告訴Django數據驅動使用pymysql

import pymysql

pymysql.install_as_MySQLdb()

  1.1.4.3) 最後在使用python3 manage.py makemigrations命令 (生成一條記錄,並沒有提交到數據庫) 創建表即可

 

    1.1.5.在windows命令行使用:python3 manage.py migrate 命令 (把生成的命令提交到數據庫執行) 創建表: (步驟二)

 

  1.1.6.數據表創建完畢後,查看:

  這些表裏面除了 "app01_book" (app01:應用名,book:表名,2者組合爲了方便區分) 這張表是自己寫的,其他都是Django默認創建的。

 

  1.1.7. 開啓Django項目,由於在models.py文件定義了創建表的數據類型,那麼訪問http://127.0.0.1:8000/即可創建數據類型(關係對象映射)

 

  1.2 對數據庫內的表結構,做修改的操作

     1.2.1.新增一條表結構 -- 在models.py文件中,直接新增一行表結構 (必須輸入默認內容及是否允許爲空:default='egon',null=True ),然後執行 python3 manage.py makemigrations (生成一條記錄,並沒有提交到數據庫)  命令:

class Book(models.Model):
    id = models.AutoField(primary_key=True)     
    title = models.CharField(max_length=32)     
    pub_date = models.DateField()               
    price = models.DecimalField(max_digits=8, decimal_places=2)
    publish = models.CharField(max_length=32,default='egon',null=True)  # default='egon':設置默認字符串,null=True:允許空值。

     執行 python3 manage.py makemigrations 命令之後,會在migtations下生成一個文件:這個文件裏面記錄了,修改後的表結構。

    operations = [
        migrations.AddField(
            model_name='book',
            name='publish',
            field=models.CharField(default='egon', max_length=32, null=True),
        ),
    ]

    需要再次執行  python3 manage.py migrate (把生成的命令提交到數據庫執行) 創建表。

 

     1.2.2.刪除一條表結構  -- 在models.py文件中,直接註釋掉一行表結構

class Book(models.Model):
    id = models.AutoField(primary_key=True)     # 生成一個主鍵:主鍵字段不可修改,如果你給某個對象的主鍵賦個新值實際上是創建一個新對象,並不會修改原來的對象。
    title = models.CharField(max_length=32)     # CharField 對應的就是varchar,用來存放字符串的
    pub_date = models.DateField()               # 日期格式
    price = models.DecimalField(max_digits=8, decimal_places=2)
    # publish = models.CharField(max_length=32)

     然後執行 python3 manage.py makemigrations (生成一條記錄,並沒有提交到數據庫) 命令,會在migrations目錄下生產一個0001_initial.py文件,這個文件裏面記錄了,修改後的表結構。

    operations = [
        migrations.CreateModel(
            name='Book',
            fields=[
                ('id', models.AutoField(primary_key=True, serialize=False)),
                ('title', models.CharField(max_length=32)),
                ('pub_date', models.DateField()),
                ('price', models.DecimalField(decimal_places=2, max_digits=8)),
            ],
        ),
    ]

    需要再次執行  python3 manage.py migrate (把生成的命令提交到數據庫執行) 創建表。

 

1.2、 如果想打印orm轉換過程中的sql,需要在settings中進行如下配置:DBUG模式

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}

# 輸出的SQL預計如下:
    SELECT `app01_study`.`id`, `app01_study`.`title`, `app01_study`.`pub_date`, `app01_study`.`price`, `app01_study`.`publish` FROM `app01_study` WHERE `app01_study`.`title` = '紅寶書'  LIMIT 21; args=('紅寶書',)
[04/Mar/2019 22:46:39] "GET /select/ HTTP/1.1" 200 2

 

  1.3 、單表操作-針對數據庫的增、刪、改、查        學習地址:https://www.cnblogs.com/liuqingzheng/articles/9472723.html

   1.3.1.添加數據

  方式一:

from app01.models import Book  # 引用models.py文件內的Book類

def orm(request):            # Book.objects表示"Book類"的一個管理器,通過這個管理器來實現"增,刪,改,查"
    # 添加數據
    # Book類,即models.py文件裏面定義的類
    # title,pub_date,price,publish 即爲表的字段
    Book.objects.create(title='python',pub_date='2015-05-11',price=199,publish='人民出版社')
    return HttpResponse('OK')

   添加完畢後,查詢數據庫內容如下:

  

 

 方式二:有返回值,就是Book對象

from app01.models import Book

def add(request):

    book=Book(title='紅寶書',price=100,pub_date='2017-8-17',publish='人民')
    book.save()

    return HttpResponse('ok')

添加完畢後,查詢數據庫內容如下:

 

   1.3.2.查詢數據

 方式一:使用Book.objects.all()拿到所有對象

from app01.models import Book
def orm(request):
    # 查詢數據
    book_list=Book.objects.all()   # Book.objects.all()拿到的是一個個對象(數據庫內的"app01_book"表,每一行數據都被實例化爲一個對象)
    for book in book_list:         # 循環對象
        print(book.title)          # 打印對象的title,pub_date,price,publish等信息
        print(book.pub_date)
        print(book.price)
        print(book.publish)
        # linux
        # 2013 - 05 - 11
        # 299.00
        # 人民出版社
    return HttpResponse('OK')

方式二:查詢單個或多個條件 Study.objects.filter(title='西遊記',id=5).first()

from app01.models import Study
def select(request):
    res=Study.objects.filter(title='西遊記',id=5)
    print(res)   # res拿到的是"QuerySet"這個對象,<QuerySet [<Study: Study object (5)>]>

    res_obj=Study.objects.filter(title='西遊記',id=5).first()  # 如果通過Study.objects.filter(title='西遊記',id=5)取到多個值的話,那麼使用.first()只取第一個值
    print(res_obj.title)   # res_obj拿到的是"一行數據"這個對象,西遊記

    return HttpResponse('ok')

方式三:使用 Study.objects.get(title='西遊記')  查詢的結果有且僅有一個,多一個或少一個都會報錯

from app01.models import Study
def select(request):
    res_get=Study.objects.get(title='西遊記')
    print(res_get)

    return HttpResponse('ok')

 

   1.3.3.刪除數據  

  方式一:Book.objects.filter(id=1).delete()  把id=1的數據給刪掉

from app01.models import Study

def orm(request):
    # 刪除數據
    Study.objects.filter(id=1).delete()   # filter爲判斷條件,查找數據表"app01_book"內,id=1的數據,delete()刪除數據。
    return HttpResponse('OK')

方式二:Study.objects.filter(title='紅寶書').first().delete() 如果Study.objects.filter(title='紅寶書')拿到的值爲多個數據,那麼.first()就是只刪除第一個數據

from app01.models import Study
def select(request):
    Study.objects.filter(title='紅寶書').first().delete()

    return HttpResponse('ok')

 

   1.3.4.修改數據  

  Study.objects.filter(title='西遊記',id=5).update(title='蘇大大',id=5) 把title='西遊記',id=5的數據修改爲title='蘇大大',id=5

from app01.models import Study

def select(request):
    Study.objects.filter(title='西遊記',id=4).update(title='蘇大大',id=4)  # 查找title='西遊記',id=4的數據,然後修改爲:title='蘇大大',id=4

    return HttpResponse('ok')

 

1.3.5、查詢API

<1> all():                  查詢所有結果
  
<2> filter(**kwargs):       它包含了與所給篩選條件相匹配的對象
  
<3> get(**kwargs):          返回與所給篩選條件相匹配的對象,返回結果有且只有一個,如果符合篩選條件的對象超過一個或者沒有都會拋出錯誤。
  
<4> exclude(**kwargs):      它包含了與所給篩選條件不匹配的對象
 
<5> order_by(*field):       對查詢結果排序('-id')
  
<6> reverse():              對查詢結果反向排序
  
<8> count():                返回數據庫中匹配查詢(QuerySet)的對象數量。
  
<9> first():                返回第一條記錄
  
<10> last():                返回最後一條記錄
  
<11> exists():              如果QuerySet包含數據,就返回True,否則返回False
 
<12> values(*field):        返回一個ValueQuerySet——一個特殊的QuerySet,運行後得到的並不是一系列
                            model的實例化對象,而是一個可迭代的字典序列
<13> values_list(*field):   它與values()非常相似,它返回的是一個元組序列,values返回的是一個字典序列
 
<14> distinct():            從返回結果中剔除重複紀錄

 

1.3.6、基於雙下劃線的模糊查詢

Book.objects.filter(price__in=[100,200,300])  # 字符串是否存在於這個列表內
Book.objects.filter(price__gt=100)    # 大於
Book.objects.filter(price__lt=100)    # 小於
Book.objects.filter(price__gte=100)   # 大於等於
Book.objects.filter(price__lte=100)   # 小於等於 
Book.objects.filter(price__range=[100,200])     # 字符串是否存在於這個range內
Book.objects.filter(title__contains="python")   # 字符串是否包含"python"
Book.objects.filter(title__icontains="python")  # 字符串"python"不區分大小寫
Book.objects.filter(title__startswith="py")     # 字符串以"py"開頭
Book.objects.filter(pub_date__year=2012)        # 時間段在2012年的字符

 

學習多表查詢之前先查看下ORM的常用字段有哪些:https://www.cnblogs.com/liuqingzheng/articles/9627915.html

 

學習地址:https://www.cnblogs.com/liuqingzheng/articles/9499252.html#_label6

二、多表操作 : 一對一,一對多,多對多(需要創建中間表才能描述多表之間的聯繫)   

  實例:首先來假定下面這些概念,字段和關係

   作者模型:一個作者有姓名和年齡。

   作者詳細模型:把作者的詳情放到詳情表,包含生日,手機號,家庭住址等信息。作者詳情模型和作者模型之間是一對一的關係(one-to-one)

   出版商模型:出版商有名稱,所在城市以及email。

   書籍模型: 書籍有書名和出版日期,一本書可能會有多個作者,一個作者也可以寫多本書,所以作者和書籍的關係就是多對多的關聯關係(many-to-many);一本書只應該由一個出版商出版,所以出版商和書籍是一對多關聯關係(one-to-many)。

 

 2.1、實例(僞代碼):根據多個表來分析,多表之間的對應關係

Publish        # 出版社
Book           # 書籍名稱(一對多)
Author         # 書籍作者:Author與AuthorDetail表之間做了對應關係
AuthorDetail   # 作者信息:Author與AuthorDetail表之間做了對應關係
Book2Author    # 書籍與作者之間的對應關係(爲了描述多對多之間的關係而創建的中間表)

CREATE TABLE publish(
                id INT PRIMARY KEY auto_increment ,
                name VARCHAR (20)
              );

CREATE TABLE book(
                id INT PRIMARY KEY auto_increment ,
                title VARCHAR (20),
                price DECIMAL (8,2),
                pub_date DATE ,
                publish_id INT ,
                FOREIGN KEY (publish_id) REFERENCES publish(id)
              );

CREATE TABLE authordetail(
                id INT PRIMARY KEY auto_increment ,
                tel VARCHAR (20)
              );

CREATE TABLE author(
                id INT PRIMARY KEY auto_increment ,
                name VARCHAR (20),
                age INT,
                authordetail_id INT UNIQUE ,
                FOREIGN KEY (authordetail_id) REFERENCES authordetail(id)
              );

CREATE  TABLE book2author(
       id INT PRIMARY KEY auto_increment ,
       book_id INT ,
       author_id INT ,
       FOREIGN KEY (book_id) REFERENCES book(id),
       FOREIGN KEY (author_id) REFERENCES author(id)
)

 

2.2、在Django中:models.py文件中 (這個文件主要是使用ORM時,定義的一些類)

from django.db import models

# Create your models here.
# 這個文件主要是使用ORM時,定義的一些類。


# 多表操作 :一對一,一對多,多對多之間的關聯關係
# 書籍出版日期表
class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()


# 書籍名稱表,與Publish表關聯
class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    # auto_now_add:插入數據的當前時間,auto_now:修改數據時的時間。
    publish_date = models.DateField()

    # "to='Publish'"表示和Publish表做關聯,to_field='nid'表示和表裏面的哪個字段做關聯
    # on_delete=models.CASCADE:級聯刪除,只要是有(OneToOneField和ForeignKey)字段的,都得加。ManyToManyField不用加
    publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)

    # 多對多的中間表,書籍表和作者表做關聯
    # "ManyToManyField"(多對多):就相當於自動創建了中間表
    authors = models.ManyToManyField(to='Author')
    """
    # 純SQL的寫法:
    CREATE  TABLE book2author(
       id INT PRIMARY KEY auto_increment ,  # book2author本身的主鍵ID
       book_id INT ,          # 字段 book_id
       author_id INT ,        # 字段 author_id
       FOREIGN KEY (book_id) REFERENCES book(id),    # 字段 book_id 關聯book表下的id字段
       FOREIGN KEY (author_id) REFERENCES author(id) # 字段 author_id author表下的id字段
)

    # Django中的寫法:
     class Book2Author(models.Model):
         nid = models.AutoField(primary_key=True)
         author_id = models.ForeignKey(to='Author',to_field='nid')
         book_id = models.ForeignKey(to='Author',to_field='nid')
    """
    def __str__(self):        # 調用這個類的時候,會自動執行這個函數
        return self.name


# 書籍對應的作者信息表,與AuthorDetail關聯(一對一)
class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)

    # 一對一之間關聯:字段"authorDetail" 對應的就是'AuthorDetail'表的字段'nid',unique=True表示唯一約束,也就是說authorDetail只能對應一個值。
    # on_delete=models.CASCADE:級聯刪除,只要是有(OneToOneField和ForeignKey)字段的,都得加。ManyToManyField不用加
    authorDetail = models.OneToOneField(to='AuthorDetail',to_field='nid',unique=True,on_delete=models.CASCADE)


# 作者本身的信息表
class AuthorDetail(models.Model):
    nid = models.AutoField(primary_key=True)
    phone = models.BigIntegerField()
    addr = models.CharField(max_length=64)

生成的表如下:

注意事項:

  1、表的名稱myapp_modelName,是根據 模型中的元數據自動生成的,也可以覆寫爲別的名稱  
  2、id 字段是自動添加的
  3、對於外鍵字段,Django 會在字段名上添加"_id" 來創建數據庫中的列名
  4、這個例子中的CREATE TABLE SQL 語句使用PostgreSQL 語法格式,要注意的是Django 會根據settings 中指定的數據庫類型來使用         相應的SQL 語句。
  5、定義好模型之後,你需要告訴Django _使用_這些模型。你要做的就是修改配置文件中的INSTALL_APPSZ中設置,在其中添加                    models.py所在應用的名稱。
  6、外鍵字段 ForeignKey 有一個 null=True 的設置(它允許外鍵接受空值 NULL),你可以賦給它空值 None 。

 

2.3、執行命令創建表:makemigrations --> migrate

2.4、多表的操作--添加表記錄

  2.4.1、一對多的數據新增

def mui_query(request):
    # 一對多的數據新增

    # 方式一:指定publish_id的方式,傳遞出版社的信息
    book1 = Book.objects.create(name='紅樓夢',price=199,publish_date='2016-09-08',publish_id=1)
    print(book1)

    # 方式二:通過獲取出版社的對象,然後把對象傳值給publish
    pub=Publish.objects.filter(name='上海出版社').first()
    book=Book.objects.create(name='金瓶梅',price=299,publish_date='2018-09-08',publish=pub)
    print(book)

    return HttpResponse('ok')

2.4.2、一對一數據新增

def mui_query(request):
    # 一對一新增

    # 方式一: 指定authorDetail_id的方式,傳遞書籍作者的信息
    author=Author.objects.create(name='wsp',authorDetail_id=2)
    print(author)

    # 方式二:通過獲取書籍作者的對象,然後把對象傳值給authorDetail!  注意:由於在models.py文件裏面設置了unique=True,所以只能一個Name對應一個authorDetail_id。如果一個authorDetail_id對應多個Name的話,就會出現1062等錯誤。
    detail=AuthorDetail.objects.filter(addr='南京').first()
    author = Author.objects.create(name='wsp', authorDetail=detail)
    print(author)

    return HttpResponse('ok')

2.4.2、多對多數據新增

def mui_query(request):
    # 多對多新增

    szq=Author.objects.filter(name='szq').first()
    wsp=Author.objects.filter(name='wsp').first()
    book = Book.objects.create(name='西遊記', price='298', publish_date='1991-09-01', publish_id=1)
    book.authors.add(szq)       # book.authors是多對多的中間表,有2個字段,分別是"book_id"和"author_id"。
                                  # book_id的值通過book.authors獲取
                                  # author_id的值通過book.authors.add(szq)獲取,其中szq=Author.objects.filter(name='szq').first()
    book.authors.add(szq,wsp)   # 也可以傳遞2個值(一本書對應2個作者)

    return HttpResponse('ok')

2.4.3、刪除多表之間的關聯關係

def mui_query(request):

    # 刪除一個關聯的數據
    szq = Author.objects.filter(name='szq').first()
    book = Book.objects.filter(name='西遊記').first()
    book.authors.remove(szq)   # 把book.authors表裏面,關於book_id的值爲'西遊記',author_id的值爲"szq"的數據刪除掉

    # 刪除所有關聯的數據
    szq = Author.objects.filter(name='szq').first()
    book = Book.objects.filter(name='西遊記').first()
    book.authors.clear()   # 把book.authors表裏面,關於book_id的值爲'西遊記'的數據全部刪除掉

    # 修改一個關聯的數據(執行的過程爲:先執行clear,然後在執行add)
    book = Book.objects.filter(name='紅寶書').first()
    book.authors.set([1,])  # 在book.authors表裏面,把book_id的值爲'紅寶書'的這一條數據的author_id的值修改爲1

    return HttpResponse('ok')

 2.4.4、核心:book.authors.all()是什麼?

def mui_query(request): 
    # 核心:book.authors.all()是什麼?   # 拿到的是book.authors表的所有數據。

    # 用法一:通過book.authors.all().values('name')直接獲取數據
    book = Book.objects.filter(name='紅寶書').first()
    ret=book.authors.all().values('name')
    print(ret)                                          # 獲取到數據作者的信息:{'name': 'sudada'}

    # 用法二:拿到一個個對象,依次取值
    book = Book.objects.filter(name='紅寶書').first()
    ret = book.authors.all().first()   # 拿到的是Author這個對象
    print(ret.name)                    # 拿到的是Author這個對象下的name的值
    print(ret.authorDetail.phone)      # 拿到的是Author這個對象下的authorDetail對象,通過authorDetail對象拿到對應phone的值


    return HttpResponse('ok')

 

2.4、多表的操作--基於對象的跨表查詢(子查詢--先查一個表,然後根據這個表查詢另外一個表,2條SQL語句完成)

 2.4.1、基於對象的多表查詢

例子一:

def mui_query(request):
    # 基於對象的多表查詢
    # 查詢紅樓夢這本書作者的名字
    book=Book.objects.filter(name='紅樓夢').first()
    res=book.authors.all()    # 查詢的是book.authors這張表的book_id字段,取出的值是book_id字段對應的多個author_id的值
    for auth in res:
        print(auth.name)

    return HttpResponse('ok')


def mui_query(request):
    # 基於對象的多表查詢
    # 查詢紅樓夢這本書出版社的名字
    book=Book.objects.filter(name='紅樓夢').first()
    print(book.publish.name)    # 北京出版社

    return HttpResponse('ok')

2.4.2:一對一 正反向查詢

# 一對一 正反向查詢

def mui_query(request):
     # 查詢作者"szq"的手機號,Author表-->AuthorDetail表,一對一正向查詢
    author = Author.objects.filter(name='szq').first()
    print(author.authorDetail.phone)

     # 查詢手機號爲"123456"對應的人的名字,AuthorDetail表-->Author表,一對一反向查詢(按照表名小寫)
    phone=AuthorDetail.objects.filter(phone='123456').first()
    print(phone.author.name)

    return HttpResponse('ok')

2.4.3:一對多 正反向查詢

def mui_query(request):

    # 一對多的正向查詢,
    # 查詢"紅樓夢"這本書的出版社地址
    book=Book.objects.filter(name="紅樓夢")
    for city in book:
        print(city.publish.city)
        # 北京
        # 北京
        # 上海

    # 一對多的反向查詢,
    # 北京出版社出版的書籍有哪些
    pub=Publish.objects.filter(name='北京出版社').first()
    for book in pub.book_set.all():
        print(book.name)
        # 紅樓夢
        # 水滸傳
        # 西遊記
        # 三國
        # 紅樓夢
    return HttpResponse('ok')

 

2.4.4::多對多 正反向查詢

# 多對多 正反向查詢

def mui_query(request):

    # 查詢紅樓夢這本書作者的名字,Book表-->Author表,多對多正向查詢
    book=Book.objects.filter(name='紅樓夢').first()
    res=book.authors.all()    # 查詢的是book.authors這張表的book_id字段,取出的值是book_id字段對應的多個author_id的值
    for auth in res:
        print(auth.name)


    # 查詢作者名爲"szq"寫的所有書籍,Author表-->Book表,多對多反向查詢
    author=Author.objects.filter(name='szq').first()
    print(author.book_set.all())  # 拿到對象: <QuerySet [<Book: 三國>, <Book: 紅樓夢>]>
    for book_name in author.book_set.all():  # 取出所有的值
        print(book_name)
        # 三國
        # 紅樓夢

    return HttpResponse('ok')

 

    2.5、正向查詢與反向查詢

    正向查詢:A表--查-->B表:關聯字段在A表中(正向查詢按照字段)
    反向查詢:B表--查-->A表:B表中沒有關聯字段。(反向查詢按照表名小寫"book_set.all()"拿到所有對象)

def mui_query(request):

    '''
    正向查詢:A表--查-->B表:關聯字段在A表中(正向查詢按照字段)
    反向查詢:B表--查-->A表:B表中沒有關聯字段。(反向查詢按照表名小寫"book_set.all()"拿到所有對象)
    '''

    # 反向查詢例子:查看"北京出版社"出版了幾本書
    pub=Publish.objects.filter(name__contains='北京出版社').first()
    print(pub.book_set.all())   # 拿到對象:<QuerySet [<Book: 紅樓夢>, <Book: 水滸傳>, <Book: 西遊記>, <Book: 三國>, <Book: 紅樓夢>]>
    for pub_name in pub.book_set.all():  # 取出所有的值
        print(pub_name)
        # 紅樓夢
        # 水滸傳
        # 西遊記
        # 三國
        # 紅樓夢

    # 正向查詢例子:查詢紅樓夢這本書出版社的名字
    book=Book.objects.filter(name='紅樓夢').first()
    print(book.publish.name)    # 北京出版社

    return HttpResponse('ok')

 

2.6、多表的操作--基於雙下劃線的跨表查詢(一條SQL語句完成查詢)  拿到的數據都是字典格式

2.6.1、一對一 正反向查詢

# 一對一 正反向查詢

def mui_query(request):
    # 查詢作者"szq"的手機號,Author表-->AuthorDetail表,一對一正向查詢
    phone = Author.objects.filter(name='szq').values('authorDetail__phone')
    print(phone)        # <QuerySet [{'authorDetail__phone': 234567}]>

    # 查詢手機號爲"123456"對應的人的名字,AuthorDetail表-->Author表,一對一反向查詢(按照表名小寫)
    name = AuthorDetail.objects.filter(phone='123456').values('author__name')
    print(name)         # <QuerySet [{'author__name': 'sudada'}]>

    return HttpResponse('ok')

  2.6.2、一對多 正反向查詢

# 一對多 正反向查詢

def mui_query(request):
    # 基於雙下劃線的跨表查詢,聯表查詢(一條SQL語句完成),正向查詢按照字段,反向查詢按照表名小寫

    # 一對多的正向查詢,按照__另一個表的字段:'publish__city'
    # 查詢"紅樓夢"這本書的出版社地址
    city=Book.objects.filter(name="紅樓夢").values('publish__city')
    print(city)    # 拿到的數據都是一個個字典 <QuerySet [{'publish__city': '北京'}, {'publish__city': '北京'}, {'publish__city': '上海'}]>


    # 一對多的反向查詢,
    # 上海出版社出版的書籍有哪些
    pub=Publish.objects.filter(name='北京出版社').values('book__name')
    for book in pub:
        '''
        拿到的都是一個個字典
        {'book__name': '水滸傳'}
        {'book__name': '西遊記'}
        {'book__name': '三國'}
        {'book__name': '紅樓夢'}
        '''
        print(book['book__name'])

    return HttpResponse('ok')

  2.6.3、多對多 正反向查詢

# 多對多 正反向查詢

def mui_query(request):
    # 多對多的正向查詢
    # 查詢"紅樓夢"這本書作者的名字
    # 通過Book表找到'紅樓夢'這本書的id,然後通過中間表"Book_Author"找到id對應的作者author_id,再通過author_id找到作者的名字
    res=Book.objects.filter(name='紅樓夢').values('authors__name')   # <QuerySet [{'authors__name': 'sudada'}, {'authors__name': 'szq'}, {'authors__name': None}, {'authors__name': 'wsp'}]>
    print(res)

    # 多對多的反向查詢
    # 查詢作者名爲"szq"寫的所有書籍,Author表 -->Book表,多對多反向查詢
    res=Author.objects.filter(name='szq').values('book__name')
    print(res)   # <QuerySet [{'book__name': '三國'}, {'book__name': '紅樓夢'}]>

    return HttpResponse('ok')

 

2.7、多表的操作--連續跨表查詢

  理解:在表A的基礎上,查詢到表B,然後查詢到表C並拿到表C的字段值(在表與表之間連續查詢時會用到正向與反向查詢)。values查詢的數據也是在表A的基礎上查詢到的(在表與表之間連續查詢時會用到正向與反向查詢)。

def mui_query(request):
    # 需求:查詢手機號以33開頭的作者,出版過的書籍名稱及書籍出版社的名字
    # 具體分析:可以通過以下4張表拿到想要的值
        # 手機號:Authordetail
        # 書名:Book
        # 豎版社名稱:Publish
        # 作者:Author

    # 方法一:以AuthorDetail表爲基準查找到作者信息,那麼後面的values也是以AuthorDetail表爲基礎查找"書籍名稱及書籍出版社的名字"
    res=AuthorDetail.objects.filter(phone__startswith='33').values('author__book__name','author__book__publish__name')
    # 在AuthorDetail表裏面,直接就可以通過匹配"phone"字段(正向查詢)。values後面的值是以AuthorDetail表爲基礎,都是通過"反向查詢拿到的"
    print(res)  # <QuerySet [{'author__book__name': '紅樓夢', 'author__book__publish__name': '北京出版社'}]>

    # 方法二:以Author表爲基準查找到作者信息,那麼後面的values也是以Author表爲基礎查找"書籍名稱及書籍出版社的名字"
    res=Author.objects.filter(authorDetail__phone__startswith='33').values('book__name','book__publish__name')
    # 在Author表裏面,需要通過authorDetail表拿到phone字段(正向查詢)。values後面的值是以Author表爲基礎,都是通過"反向查詢拿到的"
    print(res)  # <QuerySet [{'book__name': '紅樓夢', 'book__publish__name': '北京出版社'}]>

    # 方法三:以Book表爲基準查找到作者信息,那麼後面的values也是以Book表爲基礎查找"書籍名稱及書籍出版社的名字"
    book=Book.objects.filter(authors__authorDetail__phone__startswith='33').values('name','publish__name')
    # 在Book表裏面,需要通過authors表拿到authorDetail,然後拿到phone字段(正向查詢)。values後面的值是以Book表爲基礎,都是通過"正向查詢拿到的"
    print(book)  # <QuerySet [{'name': '紅樓夢', 'publish__name': '北京出版社'}]>

    # 方法四:以Publish表爲基準查找到作者信息,那麼後面的values也是以Publish表爲基礎查找"書籍名稱及書籍出版社的名字"
    pub=Publish.objects.filter(book__authors__authorDetail__phone__startswith='33').values('book__name','name')
    # 在Publish表裏面,需要通過book表拿到authors表,然後通過authors表拿到authorDetail表,然後拿到phone字段(反向查詢)。values後面的值是以Publish表爲基礎,其中'book__name'通過"反向查詢拿到的",'name'是通過"正向查詢拿到的"
    print(pub)   # <QuerySet [{'book__name': '紅樓夢', 'name': '北京出版社'}]>

    return HttpResponse('ok')

 

2.8、聚合查詢--使用aggregate(聚合函數)

def mui_query(request):
    # 聚合查詢 -- 使用aggregate:聚合函數
    # 需求:查詢所有書籍的平均價格
    # 需要先導入常用的功能,加.減.乘.除等等~
    from django.db.models import Avg,Min,Max,Count

    # 需求:查詢所有書籍的平均價格,書籍總數,書籍最高價與書籍最低價。
    res = Book.objects.all().aggregate(Avg('price'))    #書籍平均價格: {'price__avg': 221.375}
    res = Book.objects.all().aggregate(Count('name'))   #書籍總數: {'name__count': 8}
    res = Book.objects.all().aggregate(Max('price'))    #書籍最高價: {'price__max': Decimal('299.00')}
    res = Book.objects.all().aggregate(Min('price'))    #書籍最低價: {'price__min': Decimal('111.00')}

    # 一行代碼實現:可以重命名
    res = Book.objects.all().aggregate(Avg('price'),Count('name'),Max('price'),Min('price'))
    print(res)   # {'price__avg': 221.375, 'name__count': 8, 'price__max': Decimal('299.00'), 'price__min': Decimal('111.00')}

    res = Book.objects.all().aggregate(pr=Avg('price'), co=Count('name'), ma=Max('price'), mi=Min('price'))
    print(res)   # {'pr': 221.375, 'co': 8, 'ma': Decimal('299.00'), 'mi': Decimal('111.00')}

    return HttpResponse('ok')

 

2.9、F查詢與Q查詢

   2.9.1、F查詢

def mui_query(request):
    # F查詢
    # 需求:查詢"評論數"大於"閱讀數"的書籍
    from django.db.models import F
    book=Book.objects.filter(commit_num__gt=F('reat_num')).values('name')
    print(book)  # <QuerySet [{'name': '紅樓夢'}, {'name': '金瓶梅'}, {'name': '水滸傳'}, {'name': '紅寶書'}, {'name': '三國'}, {'name': '紅樓夢'}, {'name': '紅樓夢'}]>

    # 需求:紅寶書價格加100
    book = Book.objects.filter(name="紅寶書").update(price=F('price')+100)
    print(book)

    return HttpResponse('ok')

    2.9.2、Q查詢

def mui_query(request):
    # Q查詢,描述一個"與,或,非"的關係。    "|"表示或者,"&"表示且,"~"表示非
    # 需求:查詢名字爲紅樓夢或者價格大於150的書籍
    from django.db.models import Q
    book=Book.objects.filter(Q(name="紅樓夢")|Q(price__gt=200))
    print(book)  # <QuerySet [<Book: 紅樓夢>, <Book: 金瓶梅>, <Book: 西遊記>, <Book: 三國>, <Book: 紅樓夢>, <Book: 紅樓夢>]>

    # 需求:查詢名字爲紅樓夢且價格大於190的書籍
    book = Book.objects.filter(Q(name="紅樓夢") & Q(price__gt=190))
    print(book)     # <QuerySet [<Book: 紅樓夢>]>

    # Q查詢也可以Q套Q
    # 需求:查詢名字爲紅樓夢且價格大於190,或者nid大於2的書籍
    book=Book.objects.filter((Q(name="紅樓夢") & Q(price__gt=190)) | Q(nid__gt=5))
    print(book)  # <QuerySet [<Book: 紅樓夢>, <Book: 三國>, <Book: 紅樓夢>, <Book: 紅樓夢>]>

    # 需求:查詢名字不叫"紅樓夢"的書籍
    book = Book.objects.filter(~Q(name="紅樓夢"))
    print(book)  # <QuerySet [<Book: 金瓶梅>, <Book: 水滸傳>, <Book: 紅寶書>, <Book: 西遊記>, <Book: 三國>]>

    return HttpResponse('ok')

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章