Django學習筆記(7)——單表操作和多表操作


單表操作

1,創建模型

  創建名為book的APP,在book下的models.py中創建模型:

from  django.db  import models
# Create your models here.

class Book(models.Model):
    id = models.AutoField(primary_key = True)
    title=models.CharField(max_length=32)
    state=models.BooleanField()
    pub_date=models.DateField()
    price=models.DecimalField(max_digits=8,decimal_places=2)
    publish=models.CharField(max_length=32)

  

2,settings配置

  若要想將模型轉為MySQL數據庫中的表,需要在settings中配置。

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

  注意:Name名字即為數據庫的名字,在MySQL連接前該數據庫必須已經創建,而上面的SQLite數據庫下的db.sqlite3則是項目自動創建USER和PASSWORD分布式數據庫的用戶名和密碼。設置完后,再啟動我們的Django項目前,我們需要激活我們的MySQL。然后,啟動項目,會報錯:no module named MySQLdb 。這是因為django默認你導入的驅動是MySQLdb,可是MySQLdb對於py3有很大問題,所以我們需要的驅動是PyMySQL,所以我們只需要找到項目文件下的init,在里面寫入:

import pymysql

pymysql.install_as_MySQLdb()

  最后通過兩條數據庫遷移命令即可在指定數據庫中創建表:

python  manage.py  makemigrations

python  manage.py  migrate

   注意:確保配置文件中的INSTALLED_APPS中寫入我們創建的APP名稱

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    "book"
]

  注意:如果想打印ORM轉換過程中的SQL,需要在settings中進行如下配置:

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

  

APP/urls.py

from user9_one import views
from django.urls import path

urlpatterns = [
    path('book/', views.book),

]

  

ADMIN/urls.py

from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include


urlpatterns = [
    path('admin/', admin.site.urls),
    path('user7_auth/', include('user7_auth.urls')),
    path('user8_book/', include('user8_book.urls')),
    path('user9_one/', include('user9_one.urls')),
    path('user10_many/', include('user10_many.urls')),
    path('user11_ajax/', include('user11_ajax.urls')),
]

  

3,添加表記錄

3.1 create方法創建記錄對象

name=request.POST.get('name')
pwd=request.POST.get('password')
addr=request.POST.get('addr')

user=models.User.objects.create(name=name,password=pwd,address=addr)

  

3.2  創建對象,save方法保存

name=request.POST.get('name')
pwd=request.POST.get('password')
addr=request.POST.get('addr')

user=models.User(name=name,password=pwd,address=addr)
user.save()

  

3.3  示例說明

from django.shortcuts import render,HttpResponse

# Create your views here.
from user9_one.models import Book

def book(requset):
    # create 方法的返回值book_obj就是插入book表中的python1這本書的記錄
    title = 'python1'
    state = True
    price = 100
    publish = '機械出版社'
    pub_date = '2019-3-3'
    book_obj = Book.objects.create(title=title, state=state, price=price,
                                   publish=publish, pub_date=pub_date)
    title = 'python2'
    state = True
    price = 200
    publish = '機械出版社'
    pub_date = '2019-2-3'
    book_obj2 = Book(title=title, state=state, price=price,
                     publish=publish, pub_date=pub_date)
    book_obj2.save()
    return HttpResponse("create ok")

  

 

4,修改表記錄

4.1  update()方法

  注意:update方法對於任何結果集(QuerySet)有效,可以同時更新多條記錄,使用update()方法會返回一個整數數值,表示受影響的記錄條數。

name=request.POST.get('name')
pwd=request.POST.get('password')
addr=request.POST.get('addr')

models.User.objects.filter(id=id).update(name=name,password=pwd,address=addr)

 

4.2  修改對象,save()保存

# first()是返回第一條記錄
user = models.User.objects.filter(name='python').first()
user.pwd = '******'
user.save()

  

4.3  示例說明

def book(requset):
    id = 1
    title = 'python3'
    state = True
    price = 400
    publish = '機械出版社'
    pub_date = '2019-9-13'
    book_obj = Book.objects.filter(id=id).update(title=title, state=state, price=price,
                                   publish=publish, pub_date=pub_date)
    id = 2
    book_obj2 = Book.objects.filter(id=id).first()
    book_obj2.title = 'python4'
    book_obj2.state = True
    book_obj2.price = 400
    book_obj2.publish = '機械出版社'
    book_obj2.pub_date = '2019-6-13'
    book_obj2.save()
    return HttpResponse("update ok")

  

 

5,刪除表記錄

5.1 刪除所有對象

  刪除方法就是delete()。它運行時立即刪除對象而不返回任何值。例如:

model_obj.delete()

  你也可以一次性刪除多個對象,每個QuerySet都有一個delete()方法,它一次性刪除QuerySet中所有對象。

  要注意的是:delete()方法是QuerySet上的方法,但是並不適用於Manager本身。這是一種保護機制,是為了避免意外地調用Entry.objects.delete()方法導致所有的記錄被誤刪除。如果你確認要刪除所有的對象,那么你必須顯式的調用:

model.User.objects.all().delete()

  如果不想級聯刪除,可以設置為:

pubHouse = models.ForeignKey(to='Publisher', on_delete=models.SET_NULL,
 blank=True, null=True)

  

5.2  根據記錄刪除

id = request.GET.get('id')
ret1 = models.User.objects.filter(id=id).delete()
 
ret = models.Book.objects.filter(name='james').first()
ret.delete()

  

  例如,下面的代碼將刪除pub_date是2019年的Entry對象:

 Entry.objects.filter(pub_date__year=2019).delete()

  在django刪除對象時,會模仿SQL約束ON DELETE  CASCADE的行為,換句話說,刪除一個對象時也會刪除與它相關聯的外鍵對象。例如:

b = Blog.objects.get(pk=1)
# This will delete the Blog and all of its Entry objects.
b.delete()

 

5.3  示例說明

def book(requset):
    id = 7
    ret = Book.objects.filter(id=id).delete()

    Book.objects.all().delete()
    return HttpResponse("delete ok")

  

之前:

之后:

 

6,查詢記錄操作

6.1  查詢API

  查詢操作是Django的ORM框架中最重要的內容之一,下面是我們常用到與查詢相關的API

  • python數據精度存在盲點,使用查詢數字類型的是,注意轉換的SQL語句所傳輸的數字是否精確
  • 可以對QuerySet對象使用.query方法調用,可以查詢最終傳輸到數據的純生SQL語句
  • 查詢得到的QuerySet可以進行后續的查詢方法,通過.進行調用

 

   注意:一定要區分出object 和 QuerySet 的區別 !!!

  QuerySet是查詢集,就是傳到服務器上的url里面的內容,Django會對查詢返回的結果集QuerySet進行緩存,這是是為了提高查詢效率。也就是說,在創建一個QuerySet對象的時候,Django並不會立即向數據庫發出查詢命令,只有在你需要用到這個QuerySet的時候才去數據庫查詢。

  Object是django實現的MVC框架中的數據層(model)M,django中的模型類都有一個object對象,他是django中定義的QuerySet類型的對象,它包含了模型對象的實例。

  簡單來說,object是單個對象,QuerySet是許多對象。

 

 

6.2  基於雙下划線的模糊查詢

 filter(字段名__gt='') ---- 大於

 filter(字段名__lt='') ---- 小於

 filter(字段名__lte='') ---- 小於等於

 filter(字段名__gte='') ---- 大於等於

 filter(字段名__in='') ---- 字段存在列表中

 filter(字段名__range='') ---- 字段數據在范圍內(between and)

 filter(字段名__contains='') ---- 字段數據包含內容 模糊查詢 like % %

 filter(字段名__icontains='') ---- 字段數據包含內容,並且忽略大小寫 模糊查詢 like % %

 filter(字段名__startswith='') ---- 字段數據以內容開頭

 filter(字段名__endswith='') ---- 字段數據以內容結尾

 filter(字段名__year='') ---- 查詢字段內容以指定年份查詢

 filter(字段名__month='') ---- 查詢字段內容以指定月份查詢

 filter(字段名__day='') ---- 查詢字段內容以指定日期查詢

  示例:

def book(requset):
    # filter(字段名__gt='') ---- 大於
    # 查詢價格大於200 的書
    ret1 = Book.objects.filter(price__gt='200')

    # filter(字段名__lt='') ---- 小於
    # 查詢價格小於200 的書
    ret2 = Book.objects.filter(price__lt='200')

   # filter(字段名__lte='') ---- 小於等於
    ret3 = Book.objects.filter(price__lte='200')
    # filter(字段名__gte='') ---- 大於等於
    ret4 = Book.objects.filter(price__gte='200')

    # filter(字段名__in='') ---- 字段存在列表中
    ret5 = Book.objects.filter(price__in=['2001', '1000', '1001'])

    # filter(字段名__range='') ---- 字段數據在范圍內(between and)
    ret6 = Book.objects.filter(price__range=[500, 1500])

    # filter(字段名__contains='') ---- 字段數據包含內容 模糊查詢 like % %
    # 查詢名字有'%python%'的書
    ret7 = Book.objects.filter(title__contains='python')

    # filter(字段名__icontains='') ---- 字段數據包含內容,並且忽略大小寫 模糊查詢 like % %
    # 查詢名字帶p的書,忽略大小寫
    ret8 = Book.objects.filter(title__icontains='P')

    # filter(字段名__startswith='') ---- 字段數據以內容開頭
    ret9 = Book.objects.filter(title__startswith='p')

    # filter(字段名__endswith='') ---- 字段數據以內容結尾
    ret10 = Book.objects.filter(title__endswith='5')

    # filter(字段名__year='') ---- 查詢字段內容以指定年份查詢
    ret11 = Book.objects.filter(pub_date__year='2019')

    # filter(字段名__month='') ---- 查詢字段內容以指定月份查詢
    ret12 = Book.objects.filter(pub_date__month='4')

    # filter(字段名__day='') ---- 查詢字段內容以指定日期查詢
    ret13 = Book.objects.filter(pub_date__day='3')


    print(ret1)
    print(ret2)
    print(ret3)
    print(ret4)
    print(ret5)
    print(ret6)
    print(ret7)
    print(ret8)
    print(ret9)
    print(ret10)
    print(ret11)
    print(ret12)
    print(ret13)


    return HttpResponse("select ok")

 

結果:

<QuerySet [<Book: Book object (11)>, <Book: Book object (12)>, <Book: Book object (13)>, <Book: Book object (14)>, <Book: Book object (15)>, <Book: Book object (16)>]>

<QuerySet [<Book: Book object (9)>]>

<QuerySet [<Book: Book object (9)>, <Book: Book object (10)>]>

<QuerySet [<Book: Book object (10)>, <Book: Book object (11)>, <Book: Book object (12)>, <Book: Book object (13)>, <Book: Book object (14)>, <Book: Book object (15)>, <Book: Book object (16)>]>

<QuerySet [<Book: Book object (11)>, <Book: Book object (13)>, <Book: Book object (14)>]>

<QuerySet [<Book: Book object (11)>, <Book: Book object (13)>, <Book: Book object (15)>]>

<QuerySet [<Book: Book object (9)>, <Book: Book object (10)>, <Book: Book object (11)>, <Book: Book object (12)>, <Book: Book object (13)>, <Book: Book object (14)>, <Book: Book object (15)>, <Book: Book object (16)>]>

<QuerySet [<Book: Book object (9)>, <Book: Book object (10)>, <Book: Book object (11)>, <Book: Book object (12)>, <Book: Book object (13)>, <Book: Book object (14)>, <Book: Book object (15)>, <Book: Book object (16)>]>

<QuerySet [<Book: Book object (9)>, <Book: Book object (10)>, <Book: Book object (11)>, <Book: Book object (12)>, <Book: Book object (13)>, <Book: Book object (14)>, <Book: Book object (15)>, <Book: Book object (16)>]>

<QuerySet [<Book: Book object (13)>]>

<QuerySet [<Book: Book object (9)>, <Book: Book object (10)>, <Book: Book object (11)>, <Book: Book object (12)>, <Book: Book object (13)>, <Book: Book object (14)>, <Book: Book object (15)>, <Book: Book object (16)>]>

<QuerySet [<Book: Book object (12)>]>

<QuerySet [<Book: Book object (11)>, <Book: Book object (12)>, <Book: Book object (13)>, <Book: Book object (14)>, <Book: Book object (15)>, <Book: Book object (16)>]>

  

 6.3  示例說明

  首先給數據庫里面添加一些數據,添加后,數據如下:

 

def book(requset):
    # 查詢機械出版社出版的書,返回單個對象
    res = Book.objects.filter(publish="機械出版社").first()
    print(res)            # Book object(9)
    print(type(res))      # <class 'user9_one.models.Book'>

    # 支持類列表的查詢方式
    res1 = Book.objects.filter(publish="機械出版社")[1]
    print(res1)          #Book object (10)

    # filter內可以傳多個參數,用逗號分隔,他們是and的關系,返回QuerySet

    # 如果你在查詢里面,使用字符串,導致精度不准確,則會報錯,無法查詢
    res2 = Book.objects.filter(publish='機械出版社', price='100')
    print(res2)            #<QuerySet [<Book: Book object (9)>]>


    return HttpResponse("select ok")

  

 

多表操作的知識儲備

多表關聯是模型層的重要功能之一,Django提供了一套基於關聯字段獨特的解決方案。那就是用OneToOneField,ForeignKey,ManyToMany。

1,區分什么是一對一,一對多,多對多

  一對一:子表從母表中選出一條數據一一對應,母表中選出來一條就少一條,子表不可以再選擇母表中已被選擇的那條數據。

  一對多:子表從母表中選出一條數據一一對應,但母表的這條數據還可以被其他子表數據選擇。

  多對多:比如有多個孩子,多種顏色,每個孩子可以喜歡多種顏色,一種顏色可以被多個孩子喜歡,對於雙向均是可以有多個選擇。

2,一對一,一對多,多對多的應用場景

  一對一(OneToOneField):一般用於某張表的補充,比如用戶基本信息是一張表,但並非每個用戶都需要有登錄的權限,不需要記錄用戶名和密碼,此時,合理的做法就是新建一張記錄登錄信息的表,與用戶信息進行一對一的關聯,可以方便的從子表查詢母表信息或反向查詢

  外鍵(ForeignKey):有很多的應用場景,比如每個員工歸屬於一個部門,那么就可以讓員工表的部門字段與部門表進行一對多關聯,可以查詢到一個員工歸屬於哪個部門,也可以反向查詢某一部門有哪些員工

  多對多(ManyToMany):如有很多公司,一台服務器可能會有很多種用途,歸屬於多個產品線中,那么服務器與產品線之間就可以做成多對,多對多在A表添加ManyToMany字段或者從B表中添加,效果一樣。

3,外鍵——ForeignKey

  ForeignKey 字段接受一個Model類作為參數,類型與被參照的字段完全相同:

blog = models.ForeignKey(Blog)

 

3.1  ForeignKey.to_field

  關聯到的關聯對象的字段名稱。默認的,Django使用關聯對象的主鍵。

blog = models.ForeignKey(Blog, to_field = Blog.name)

  

3.2  ForeignKey.db_constraint

  Django Model的 Foreign 字段的主要功能是維護一個一對多的關系,以進行關聯查詢。只有在db_constraint = True 時Django model 才會在數據庫上建立外鍵約束,在該值為False時不建立約束。

  默認 db_constraint = True

3.3  ForeignKey.related_name

  這個名稱用於讓關聯的對象反查到源對象。

  如果你不想讓DJango創建一個反向關聯,請設置related_name 為 ‘+’ 或者 以‘+’結尾。

  ForeignKey.related_query_name以ForeignKey.related_name作為默認值。

 

4,ManyToManyField

4.1  ManyToManyField.through

  Django會自動創建一個表來管理多對多關系,若要手動指定關聯表則需要使用through關鍵字參數。

4.2   ManyToManyField.through_fields

  上面示例中Membership有兩個外鍵指向Person(person 和 inviter),這使得關聯關系含混不清並讓Django不知道使用哪一個,在這種情況下,必須使用through_fields明確指定Django應該使用哪些外鍵。through_fields 接收一個二元組('field1' , 'field2'),其中field1為指向定義ManyToManyField字段的模型的外鍵名稱(本例中為group),field2為指向目標模型的外鍵的名稱(本例中為person)。

4.3  MantToManyField.db_table

  默認情況下,關聯表的名稱使用多對多字段的名稱和包含這張表的模型的名稱以及Hash值生成,如:memberShip_person_3c1f5,若想要手動指定表的名稱,可以使用db_table 關鍵字參數指定。

5,on_delete的使用方法

  對於最新版本的Django2.0 在使用一對一(OneToOneField)和外鍵(ForeignKey)時,需要加上on_delete 參數,不然就會報錯,

  如果剛使用django2.0 的是,遇到報錯如下,則是沒有給外鍵添加on_delete參數:

TypeError: __init__() missing 1 required positional argument: 'on_delete'

6,一對一(OneToOneField)示例

from django.conf import settings
from django.db import models

class MySpecialUser(models.Model):
    user = models.OneToOneField(settings.AUTH_PASSWORD_VALIDATORS, on_delete=models.CASCADE,)
    supervisor = models.OneToOneField(settings.AUTH_PASSWORD_VALIDATORS, on_delete=models.CASCADE,
                                      related_name='supervisor_of',)
    

  

7,一對多(ForeignKey)示例

from django.db import models
class AbstractCar(models.Model):
    manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
    class Meta:
        abstract = True

8,下面整理的on_delete參數的各個值的含義:

on_delete=None,               
# 刪除關聯表中的數據時,當前表與其關聯的field的行為

on_delete=models.CASCADE,     
# 刪除關聯數據,與之關聯也刪除

on_delete=models.DO_NOTHING,  
# 刪除關聯數據,什么也不做

on_delete=models.PROTECT,     
# 刪除關聯數據,引發錯誤ProtectedError

# models.ForeignKey('關聯表', on_delete=models.SET_NULL, blank=True, null=True)
on_delete=models.SET_NULL,    
# 刪除關聯數據,與之關聯的值設置為null(前提FK字段需要設置為可空,一對一同理)

# models.ForeignKey('關聯表', on_delete=models.SET_DEFAULT, default='默認值')
on_delete=models.SET_DEFAULT, 
# 刪除關聯數據,與之關聯的值設置為默認值(前提FK字段需要設置默認值,一對一同理)

on_delete=models.SET,         
# 刪除關聯數據,
 a. 與之關聯的值設置為指定值,設置:models.SET(值)
 b. 與之關聯的值設置為可執行對象的返回值,設置:models.SET(可執行對象)

  多對多不需要on_delete。

 

 多表操作

1,創建模型

1.1  實例:我們來假定下面這些概念,字段和關系

作者模型            :   姓名  年齡


作者詳細模型      :   生日   手機號碼   家庭住址等等


出版商模型          :   出版商名稱   所在城市   email


書籍模型            :   書名  出版日期


(作者模型  和 作者詳細模型  是一對一關系  one-to -one)
(一本書可能會有多個作者, 一個作者也可以寫多本書)
(作者  和 書籍 是多對多的關系  many -to -many)
(一本書只應該由一個出版商出版, 出版商和書籍是一對多關聯關系  one - to  - many)

 

1.2  代碼如下

from django.db import models

# Create your models here.
class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    # 與AuthorDetail建立一對一的關系
    authorDetail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)

class AuthorDetail(models.Model):
    nid = models.AutoField(primary_key=True)
    birthday = models.DateField()
    telephone = models.BigIntegerField()
    addr = models.CharField(max_length=64)

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

class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    publishDate = models.DateField()
    # max_digits=None, 總長度    decimal_places=None,小數位長度
    price = models.DecimalField(max_digits=5, decimal_places=2)

    # 與publish建立一對多的關系,外鍵字段建立在多的一方
    publish = models.ForeignKey(to='Publish', to_field='nid',on_delete=models.CASCADE)

    # 與Author 建立多對多的關系,ManyToManyField可以建在兩個模型中的任意一個,自動創建第三張表
    authors = models.ManyToManyField(to='Author',)

 

1.3  結果如下

1.4  注意事項

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

 

2,添加表記錄

  操作前先簡單的錄入一些數據

2.1  Publish表

2.2  AuthorDetail表

 

 2.3  Author表

 

 2.4  一對多添加——book表

def insert_data(request):
    publish_obj = Publish.objects.get(nid=1)
    book_obj = Book.objects.create(title='秦腔', publishDate='2016-8-28', price=1005, publish=publish_obj)

    book_obj2 = Book.objects.create(title="追風箏的人", publishDate='2017-4-9', price=124, publish_id=2)
    return HttpResponse("insert data ok")

  

2.5  多對多添加——book表,book_authors表

def insert_data(request):
    # 生成當前的書籍對象
    book_obj = Book.objects.create(title='秦腔', publishDate='2016-8-28', price=1005, publish_id=1)

    # 為書籍綁定的做作者對象
    author_james = Author.objects.filter(name='james').first()   # 在Author表中主鍵為1的記錄
    author_durant = Author.objects.filter(name='durant').first()  # 在Author表中主鍵為2的記錄

    # 綁定多對多關系,即向關系表book_authors中添加數據
    book_obj.authors.add(author_james, author_durant)
    # 將某些特定的model對象添加到被關聯對象集合中
    # book_obj.authors.add(*[])
    return HttpResponse("insert data ok")

  

2.6  多對多關系常用API

# 將某個特定的對象從被關聯對象集合中去除。  
book_obj.authors.remove()       
book_obj.authors.remove(*[])

#清空被關聯對象集合
book_obj.authors.clear()     

 #先清空再設置  
book_obj.authors.set()        

  

  create(**kwargs)

創建一個新的對象,保存對象,並將它添加到關聯對象集之中。返回新創建的對象:

>>> b = Blog.objects.get(id=1)
>>> e = b.entry_set.create(
...     headline='Hello',
...     body_text='Hi',
...     pub_date=datetime.date(2005, 1, 1)
... )

# No need to call e.save() at this point -- it's already been saved.
這完全等價於(不過更加簡潔於):

>>> b = Blog.objects.get(id=1)
>>> e = Entry(
...     blog=b,
...     headline='Hello',
...     body_text='Hi',
...     pub_date=datetime.date(2005, 1, 1)
... )
>>> e.save(force_insert=True)
要注意我們並不需要指定模型中用於定義關系的關鍵詞參數。在上面的例子中,我們並沒有
傳入blog參數給create()。Django會明白新的 Entry對象blog 應該添加到b中。

  

   remove(obj1 [, obj2,...])

從關聯對象集中移除執行的模型對象:

>>> b = Blog.objects.get(id=1)
>>> e = Entry.objects.get(id=234)
>>> b.entry_set.remove(e) # Disassociates Entry e from Blog b.
對於ForeignKey對象,這個方法僅在null=True時存在。

  

  clear()

從關聯對象集中移除一切對象。

>>> b = Blog.objects.get(id=1)
>>> b.entry_set.clear()
注意這樣不會刪除對象 —— 只會刪除他們之間的關聯。

就像 remove() 方法一樣,clear()只能在 null=True的ForeignKey上被調用。

  

   set()

  先清空,再設置,編輯書籍時即可用到

 

  注意:對於所有類型的關聯字段,add() ,create(),remove(),clear(),set() 都會馬上更新數據庫。換句話說,在關聯的任何一端,都不需要再調用save()方法。

  直接賦值:通過賦值一個新的可跌打的對象,關聯對象集可以被整體替換掉

>>> new_list = [obj1, obj2, obj3]
>>> e.related_set = new_list

  如果外鍵關系滿足 null =True,關聯管理器會在添加new_list 中的內容之前,首先調用clear()方法來解除關聯集中一切已存在對象的關聯。否則 , new_list中的對象會在已存在的關聯的基礎上被添加。

 

2.7  如何處理外鍵關系的字段(如一對多的publisher和多對多的authors)

#一對多(ForeignKey):
 
    # 方式一: 由於綁定一對多的字段,比如publish,存到數據庫中的字段名叫publish_id
    # 所以我們可以直接給這個
    #       字段設定對應值:
           Book.objects.create(title='php',
                               publisher_id=2,   #這里的2是指為該book對象綁定了Publisher表中id=2的行對象
                               publication_date='2017-7-7',
                               price=99)
 
 
    #方式二:
    #       <1> 先獲取要綁定的Publisher對象:
        pub_obj=Publisher(name='河大出版社',address='保定',city='保定',
                state_province='河北',country='China',website='http://www.hbu.com')
    OR  pub_obj=Publisher.objects.get(id=1)
 
    #       <2>將 publisher_id=2 改為  publisher=pub_obj
 
#多對多(ManyToManyField()):
 
    author1=Author.objects.get(id=1)
    author2=Author.objects.filter(name='alvin')[0]
    book=Book.objects.get(id=1)
    book.authors.add(author1,author2)
    #等同於:
    book.authors.add(*[author1,author2])
    book.authors.remove(*[author1,author2])
    #-------------------
    book=models.Book.objects.filter(id__gt=1)
    authors=models.Author.objects.filter(id=1)[0]
    authors.book_set.add(*book)
    authors.book_set.remove(*book)
    #-------------------
    book.authors.add(1)
    book.authors.remove(1)
    authors.book_set.add(1)
    authors.book_set.remove(1)
 
#注意: 如果第三張表是通過models.ManyToManyField()自動創建的,那么綁定關系只有上面一種方式
#     如果第三張表是自己創建的:
     class Book2Author(models.Model):
            author=models.ForeignKey("Author")
            Book=  models.ForeignKey("Book")
#     那么就還有一種方式:
            author_obj=models.Author.objects.filter(id=2)[0]
            book_obj  =models.Book.objects.filter(id=3)[0]
 
            s=models.Book2Author.objects.create(author_id=1,Book_id=2)
            s.save()
            s=models.Book2Author(author=author_obj,Book_id=1)
            s.save()

  

2.8 對象查詢,單表條件查詢,多表條件關聯查詢

#--------------------對象形式的查找--------------------------
    # 正向查找
    ret1=models.Book.objects.first()
    print(ret1.title)
    print(ret1.price)
    print(ret1.publisher)
    print(ret1.publisher.name)  #因為一對多的關系所以ret1.publisher是一個對象,
而不是一個queryset集合
 
    # 反向查找
    ret2=models.Publish.objects.last()
    print(ret2.name)
    print(ret2.city)
    #如何拿到與它綁定的Book對象呢?
    print(ret2.book_set.all()) #ret2.book_set是一個queryset集合
 
#---------------了不起的雙下划線(__)之單表條件查詢----------------
 
#    models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 獲取id大於1 且 小於10的值
#
#    models.Tb1.objects.filter(id__in=[11, 22, 33])   # 獲取id等於11、22、33的數據
#    models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
#
#    models.Tb1.objects.filter(name__contains="ven")
#    models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感
#
#    models.Tb1.objects.filter(id__range=[1, 2])   # 范圍bettwen and
#
#    startswith,istartswith, endswith, iendswith,
 
#----------------了不起的雙下划線(__)之多表條件關聯查詢---------------
 
# 正向查找(條件)
 
#     ret3=models.Book.objects.filter(title='Python').values('id')
#     print(ret3)#[{'id': 1}]
 
      #正向查找(條件)之一對多
 
      ret4=models.Book.objects.filter(title='Python').values('publisher__city')
      print(ret4)  #[{'publisher__city': '北京'}]
 
      #正向查找(條件)之多對多
      ret5=models.Book.objects.filter(title='Python').values('author__name')
      print(ret5)
      ret6=models.Book.objects.filter(author__name="alex").values('title')
      print(ret6)
 
      #注意
      #正向查找的publisher__city或者author__name中的publisher,author是book表中綁定的字段
      #一對多和多對多在這里用法沒區別
 
# 反向查找(條件)
 
    #反向查找之一對多:
    ret8=models.Publisher.objects.filter(book__title='Python').values('name')
    print(ret8)#[{'name': '人大出版社'}]  注意,book__title中的book就是Publisher的關聯表名
 
    ret9=models.Publisher.objects.filter(book__title='Python').values('book__authors')
    print(ret9)#[{'book__authors': 1}, {'book__authors': 2}]
 
    #反向查找之多對多:
    ret10=models.Author.objects.filter(book__title='Python').values('name')
    print(ret10)#[{'name': 'alex'}, {'name': 'alvin'}]
 
    #注意
    #正向查找的book__title中的book是表名Book
    #一對多和多對多在這里用法沒區別

  注意:條件查詢即與對象查詢對應,是指在filter,values等方法中通過__來明確查詢條件

 3,關聯管理器——Class  RelatedManager

  “關聯管理器” 是在一對多或者多對多的關聯上下文中使用的管理器。他存在於下面兩種情況:ForeignKey關系的“另一邊”。像這樣:

# models.py
from django.db import models

class Reporter(models.Model):
    # ...
    pass

class Article(models.Model):
    reporter = models.ForeignKey(Reporter)

  在上面的例子中,管理器reporter.article_set擁有下面的方法。

MangToManyField關系的兩邊:

class Manager1(models.Model):
    # ...
    pass

class Manager2(models.Model):
    manager1 = models.ManyToManyField(Manager1)

 

3.1  查詢表記錄(filter,value)

    查詢操作是Django的ORM框架中最重要的內容之一,下面是我們常用到與查詢相關的API。

  注意:一定要區分出object 和QuerySet 的區別

附加SQL查詢extra()

#擴展查詢,有時候DJANGO的查詢API不能方便的設置查詢條件,提供了另外的擴展查詢方法extra:
#extra(select=None, where=None, params=None, tables=None,order_by=None, select_params=None
  
(1)  Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})

(2)  Blog.objects.extra(
        select=SortedDict([('a', '%s'), ('b', '%s')]),
        select_params=('one', 'two'))
  
(3)  q = Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
     q = q.extra(order_by = ['-is_recent'])
  
(4)  Entry.objects.extra(where=['headline=%s'], params=['Lennon'])

  

4,基於對象的跨表查詢

4.1  一對一查詢(Author和AuthorDetail)

正向查詢(按字段:authorDetail)

def select_data(request):
  # 查詢作者名為james的電話
    james = Author.objects.filter(name='james').first()
    print(james)
    print(james.authorDetail.telephone)

    return HttpResponse("select data ok")

  

 

反向查詢(按表名:author)

def select_data(request):
    # 查詢住址在chengdu的作者姓名
    authorDetail_list = AuthorDetail.objects.filter(addr='chengdu')
    for obj in authorDetail_list:
        print(obj.author.name)

    return HttpResponse("select data ok")

  

 

4.2  一對多查詢(Publish和Book)

 正向查詢(按字段:publish)

def select_data(request):
    # 查詢主鍵為1的書籍的出版社所在的城市
    book_obj = Book.objects.filter(nid=1).first()
    # book_obj.publish 是主鍵為1 的書籍對象關聯的出版社對象
    print(book_obj.publish.city)

    return HttpResponse("select data ok")

  

 

 反向查詢(按表名:book_set)

def select_data(request):
    publish = Publish.objects.get(name="機械出版社")
    # 與機械出版社 關聯的所有書籍對象集合
    res1 = publish.book_set.all()
    print(res1)
    book_list = publish.book_set.all()
    for book_obj in book_list:
        print(book_obj.title)

    return HttpResponse("select data ok")

  

 

 4.3  多對多查詢(Author與Book)

正向查詢(按字段:author)

def select_data(request):
    # 查找平凡的世界所有作者的名字以及手機號碼
    book_obj = Book.objects.filter(title="秦腔").first()
    print(book_obj)
    authors = book_obj.authors.all()
    print(authors)
    for author_obj in authors:
        print(author_obj.name, author_obj.authorDetail.telephone)

    return HttpResponse("select data ok")

  

反向查詢(按表名:book_set)

def select_data(request):
    # 查找james出過的所有書籍的名字
    author_obj = Author.objects.get(name='james')
    print(author_obj)
    # 與james作者相關的所有書籍
    book_list = author_obj.book_set.all()
    print(book_list)
    for book_obj in book_list:
        print(book_obj.title)

    return HttpResponse("select data ok")

  

 

 4.4  注意

   你可以通過在ForeignKey()和ManyToManyField的定義中設置related_name的值來覆寫FOO_set的名稱。例如,如果Article  model中做一下更改:

publish = ForeignKey(Book, related_name='bookList')

  那么接下來,我們就會看到這樣:

def select_data(request):
    # 查找人們出版社出版過的所有書籍
    publish = Publish.objects.get(name='機械出版社')
    print(publish)
    # 與機械出版社關聯的所有書籍對象集合
    book_list = publish.bookList.all()
    print(book_list)
    return HttpResponse("select data ok")

  

 

5,基於雙下划線的跨表查詢

  Django還提供了一種直觀而高效的方法在查詢(lookups)中表示關聯關系,它能自動確認SQL JOIN 聯系。要做跨關系查詢,就使用兩個下划線來鏈接模型(model)間關聯字段的名稱,直到最終鏈接到你想要的model為止。

   關鍵點:正向查詢按字段,反向查詢按表名

5.1  一對多查詢

def select_data(request):
    # 查詢機械出版社 出版過的所有書籍的名字與價錢(一對多)
    # 正向查詢  按字段publish
    queryResult1 = Book.objects.filter(publish_id=1).values_list('publish__book', 'publish__city')
    print(queryResult1)
    # 反向查詢  按表名:book
    queryResult2 =Publish.objects.filter(nid=2).values_list("book__title", 'book__price')
    print(queryResult2)

    return HttpResponse("select data ok")

  

 查詢結果:

<QuerySet [(1, 'xian'), (3, 'xian'), (4, 'xian'), (5, 'xian'), (6, 'xian'), (1, 'xian'), 
(3, 'xian'), (4, 'xian'), (5, 'xian'), (6, 'xian'), (1, 'xian'), (3, 'xian'), (4, 'xian'),
 (5, 'xian'), (6, 'xian'), (1, 'xian'), (3, 'xian'), (4, 'xian'), (5, 'xian'), (6, 'xian'), '
...(remaining elements truncated)...']>

<QuerySet [('追風箏的人', Decimal('124.00'))]>

  

5.2  多對多查詢

def select_data(request):
    # 查詢james出版過的所有書籍的名字 (多對多)
    # 正向查詢,按照字段:authors
    queryResult1 = Book.objects.filter(authors=1).values_list("authors__name",'authors__age','publish__name')
    print(queryResult1)
    # 反向查詢  按照表名book
    queryResult2 = Author.objects.filter(name='durant').values_list("book__authors__name",'age','book__publish__name')
    print(queryResult2)
    return HttpResponse("select data ok")

  結果展示:

<QuerySet [('james', 34, '機械出版社'), ('james', 34, '機械出版社')]>


<QuerySet [('james', 30, '機械出版社'), ('james', 30, '機械出版社'), 
('durant', 30, '機械出版社'), ('durant', 30, '機械出版社')]>

 

5.3 一對一查詢

# 查詢james的手機號
    
    # 正向查詢
    ret=Author.objects.filter(name="james").values("authordetail__telephone")

    # 反向查詢
    ret=AuthorDetail.objects.filter(author__name="james").values("telephone")

  

5.4  混合使用

def select_data(request):
    # 查詢機械出版社 出版過的所有書籍的名字與作者名字
    # 正向查詢 按照字段 authors
    queryResult1 = Book.objects.filter(publish_id=1).values_list('title', 'authors__name')
    print(queryResult1)

    # 反向查詢  按表名:book
    queryResult2 =Publish.objects.filter(nid=2).values_list("book__title", 'book__price')
    print(queryResult2)

    # 查詢手機是以123開頭的作者  出版過的所有書籍名稱以及出版社名稱
    queryResult3 = Book.objects.filter(authors__authorDetail__telephone__regex='123').values_list('title', 'publish__name')
    print(queryResult3)
    return HttpResponse("select data ok")

  結果展示:

<QuerySet [('秦腔', 'james'), ('秦腔', 'james'), ('秦腔', 'durant'), ('秦腔', 'durant'), 
('平凡的世界', None), ('平凡的世界2', None), ('秦腔', None)]>

<QuerySet [('追風箏的人', Decimal('124.00'))]>

<QuerySet [('秦腔', '機械出版社'), ('秦腔', '機械出版社')]>

  

  注意:反向查詢時,如果定義了related_name,則用related_name替換表名,例如:

publish = ForeignKey(Blog, related_name='bookList')

  

5.5  練習:查詢人民出版社出版過的所有書籍的名字與價格(一對多)

def select_data(request):
    # 查詢機械出版社 出版過的所有書籍的名字與價格
    # 正向查詢 按照字段 authors
    queryResult1 = Book.objects.filter(publish_id=1).values_list('title', 'price')
    print(queryResult1)

    #  反向查詢   不再按照表名book,而是related_name:bookList
    queryResult2 = Publish.objects.filter(name='機械出版社').values_list("book__title","book__price")
    print(queryResult2)

    return HttpResponse("select data ok")

  結果展示:

<QuerySet [('平凡的世界', Decimal('125.00')), ('平凡的世界2', Decimal('105.00')), 
('秦腔',Decimal('1005.00')), ('秦腔', Decimal('1005.00')), ('秦腔', Decimal('1005.00'))]>

<QuerySet [('平凡的世界', Decimal('125.00')), ('平凡的世界2', Decimal('105.00')),
 ('秦腔',Decimal('1005.00')), ('秦腔', Decimal('1005.00')), ('秦腔', Decimal('1005.00'))]>

 

5.6  進階練習(連續跨表)

# 練習: 查詢人民出版社出版過的所有書籍的名字以及作者的姓名


    # 正向查詢
    queryResult=Book.objects
            .filter(publish__name="人民出版社")
            .values_list("title","authors__name")
    # 反向查詢
    queryResult=Publish.objects
              .filter(name="人民出版社")
              .values_list("book__title","book__authors__age","book__authors__name")


# 練習: 手機號以151開頭的作者出版過的所有書籍名稱以及出版社名稱


    # 方式1:
    queryResult=Book.objects
            .filter(authors__authorDetail__telephone__regex="151")
            .values_list("title","publish__name")
    # 方式2:    
    ret=Author.objects
              .filter(authordetail__telephone__startswith="151")
              .values("book__title","book__publish__name")

  

5.7  related_name

  反向查詢時,如果定義了related_name,則使用 related_name替換表名,例如:

publish = ForeignKey(Blog, related_name='bookList')

  練習:

# 練習: 查詢人民出版社出版過的所有書籍的名字與價格(一對多)

# 反向查詢 不再按表名:book,而是related_name:bookList


    queryResult=Publish.objects
              .filter(name="人民出版社")
              .values_list("bookList__title","bookList__price")

  

6 ,聚合查詢和分組查詢

6.1  aggregate(*args , **kwargs):

  通過對QuerySet進行計算,返回一個聚合值的字典,aggregate()中每一個參數都指定一個包含在字典中的返回值。即在查詢集上生成聚合。

  總結:跨表分組查詢的本質就是將關聯表join成一張表,再按照單表的思路進行分組查詢。

  aggregate()字句的參數描述了我們想要計算的聚合值。aggregate() 是QuerySet的一個終止子句,意思是它返回一個包含一些鍵值對的字典,鍵的名稱是聚合值的標識符,值是計算出來的聚合值。鍵的名稱是按照字段和聚合函數的名稱自動生成出來的。如果你想要為聚合值指定一個名稱,可以向聚合子句提供它。 

from django.db.models import Avg, Min, Sum, Max
def select_data(request):
    # 比如你想要計算所有在售的書的平均價錢
    # Django 提供了一種方式描述所有圖書的集合
    # 在下面的例子中,aggregate()計算的Book模型中price字段的平均值
    res1 = Book.objects.all().aggregate(Avg('price'))
    print(res1)          #{'price__avg': 561.5}


    # 如果想要為聚合值指定一個名稱,可以向聚合子句提供它。
    res2 = Book.objects.aggregate(avergae_price=Avg('price'))
    print(res2)        # {'avergae_price': 561.5}

    # 如果你想知道所有圖書價格的最大值和最小值,可以這樣查詢
    res3 = Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
    print(res3)
    # {'price__avg': 561.5, 'price__max': Decimal('1005.00'), 'price__min': Decimal('105.00')}

    return HttpResponse("select data OK")

  

6.2  annotate( *args , **kwargs)

  可以通過計算查詢結果中每一個對象所關聯的對象集合,從而得到總計值(也可以是平均值或者總和),即為查詢集的每一項生成聚合。

  單表分組查詢的ORM 語法如下:單表模型.objects.values('group by 的字段‘).annotate(聚合函數('統計字段'))

  查詢各個作者出的書的總價格,這里就涉及到分組了,分組條件是authors_name

  查詢各個出版社最便宜的書價是多少

from django.db.models import Avg, Min, Sum, Max

def select_data(request):
    #  查詢各個作者出的書的總價格,這里涉及分組,分組條件是authors_name
    res1 = Book.objects.values("authors__name").annotate(Sum('price'))
    print(res1)
    
    # 查詢各個出版社最便宜的書架是多少
    res2 = Book.objects.values("publish__name").annotate(Min("price"))
    print(res2)

    return HttpResponse("select data OK")

  結果如下:

<QuerySet [{'authors__name': 'james', 'price__sum': Decimal('2010.00')}, 
{'authors__name':'durant', 'price__sum': Decimal('2010.00')}, 
{'authors__name': None, 'price__sum': Decimal('1359.00')}]>


<QuerySet [{'publish__name': '機械出版社', 'price__min': Decimal('105.00')}, 
{'publish__name':'清華出版社', 'price__min':Decimal('124.00')}]>

  

6.3 查詢練習

  注意:(框里面的相等)

 

 

1,練習:統計每一個出版社里最便宜的書籍

publishList = Publish.objetcs.annotate(minPrice=Min('book__price"))
for publish_obj in publishList:
    print(publish_obj.name, publish_obj.MinPrice)

  annotate的返回值是QuerySet,如果不想遍歷對象,可以用上 valuelist

queryResult= Publish.objects
            .annotate(MinPrice=Min("book__price"))
            .values_list("name","MinPrice")
print(queryResult)

  對應的SQL代碼如下:

'''
SELECT "app01_publish"."name", MIN("app01_book"."price")  AS "MinPrice" FROM "app01_publish" 
LEFT  JOIN "app01_book" ON ("app01_publish"."nid" = "app01_book"."publish_id") 
GROUP BY "app01_publish"."nid", "app01_publish"."name", "app01_publish"."city", "app01_publish"."email" 

'''

  

2,練習:統計每一本書的作者個數

ret = Book.objects.annotate(authorsNum=Count('authors__name'))

  

3,統計每一本以py開頭的書籍的作者個數

queryResult=Book.objects.filter(title__startswith="Py")
           .annotate(num_authors=Count('authors'))

  

4,統計不止一個作者的圖書:

queryResult=Book.objects.annotate(num_authors=Count('authors'))
          .filter(num_authors__gt=1)

  

5,根據一本圖書作者數量的多少對查詢集QuerySet進行排序

Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors')

  

6,查詢各個作者出的書的總價格

#   按author表的所有字段 group by
    queryResult=Author.objects.annotate(SumPrice=Sum("book__price"))
              .values_list("name","SumPrice")
    print(queryResult)

  

 

7,F查詢和Q查詢

  僅僅靠着單一的關鍵字參數查詢已經很難滿足查詢要求。此時Django為我們提供了F和Q查詢:

7.1  F查詢

  F()的實例可以在查詢中引用字段,來比較同一個model實例中兩個不同字段的值。

# 查詢評論數大於收藏數的書籍
 
   from django.db.models import F
   Book.objects.filter(commnetNum__lt=F('keepNum'))

  Django支持F() 對象之間以及F()對象和常數之間的加減乘除和取模的操作

# 查詢評論數大於收藏數2倍的書籍

    Book.objects.filter(commnetNum__lt=F('keepNum')*2)

 

  修改操作也可以使用F函數,比如把每一本書的價格提高10元

def update_use_F(request):
    # F 使用查詢條件的值,專門取對象中某列值的操作
    from django.db.models import F
    # models.Tb1.objects.update(num=F('num') + 1)
    res1 = Book.objects.update(price = F('price') + 10)
    print(res1)
    return HttpResponse("update use F OK")

  操作之前:

  操作之后:

 

7.2   Q() 查詢

  filter()等方法中的關鍵字參數查詢都是一起“AND”的,如果你需要執行更復雜的查詢(例如OR語句),你可以使用Q 對象。

from django.db.models import Q
Q(title__startswith='Py')

  Q 對象可以使用& 和| 操作符組合起來。當一個操作符在兩個Q 對象上使用時,它產生一個新的Q 對象。

bookList=Book.objects.filter(Q(authors__name="james")|Q(authors__name="durant"))

  等同於SQL WHERE字句:

WHERE name ="james" OR name ="durant"

  你可以組合& 和| 操作符以及使用括號進行分組來編寫任意復雜的Q 對象。同時,Q 對象可以使用~ 操作符取反,這允許組合正常的查詢和取反(NOT) 查詢:

bookList=Book.objects.filter(Q(authors__name="james") &
 ~Q(publishDate__year=2017)).values_list("title")

  查詢函數可以混合使用Q 對象和關鍵字參數。所有提供給查詢函數的參數(關鍵字參數或Q 對象)都將"AND”在一起。但是,如果出現Q 對象,它必須位於所有關鍵字參數的前面。例如:

bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017),
                              title__icontains="python"
                             )

  

7.3   綜合運用

# F 使用查詢條件的值,專門取對象中某列值的操作

    # from django.db.models import F
    # models.Tb1.objects.update(num=F('num')+1)


# Q 構建搜索條件
    from django.db.models import Q

    #1 Q對象(django.db.models.Q)可以對關鍵字參數進行封裝,從而更好地應用多個查詢
    q1=models.Book.objects.filter(Q(title__startswith='P')).all()
    print(q1)#[<Book: Python>, <Book: Perl>]

    # 2、可以組合使用&,|操作符,當一個操作符是用於兩個Q的對象,它產生一個新的Q對象。
    Q(title__startswith='P') | Q(title__startswith='J')

    # 3、Q對象可以用~操作符放在前面表示否定,也可允許否定與不否定形式的組合
    Q(title__startswith='P') | ~Q(pub_date__year=2005)

    # 4、應用范圍:

    # Each lookup function that takes keyword-arguments (e.g. filter(),
    #  exclude(), get()) can also be passed one or more Q objects as
    # positional (not-named) arguments. If you provide multiple Q object
    # arguments to a lookup function, the arguments will be “AND”ed
    # together. For example:

    Book.objects.get(
        Q(title__startswith='P'),
        Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
    )

    #sql:
    # SELECT * from polls WHERE question LIKE 'P%'
    #     AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

    # import datetime
    # e=datetime.date(2005,5,6)  #2005-05-06

    # 5、Q對象可以與關鍵字參數查詢一起使用,不過一定要把Q對象放在關鍵字參數查詢的前面。
    # 正確:
    Book.objects.get(
        Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
        title__startswith='P')
    # 錯誤:
    Book.objects.get(
        question__startswith='P',
        Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))

  

 

8,刪除表記錄(delete)

  刪除方法就是delete() 它運行時立即刪除對象而不返回任何值。例如:

model_obj.delete()

  你可以一次性刪除多個對象,每個QuerySet都有一個delete()方法,它一次性刪除QuerySet中所有的對象。

  例如下面的代碼將刪除pub_date是2005年的Entry對象:

Entry.objects.filter(pub_date__year=2005).delete()

  在Django刪除對象時,會模仿SQL約束ON DELETE CASCADE的行為,換句話說,刪除一個對象時也會刪除與它相關聯的外鍵對象。例如:

b = Blog.objects.get(pk=1)
# This will delete the Blog and all of its Entry objects.
b.delete()

  要注意的是:delete() 方法就是QuerySet上的方法,但並不適用於Manager本身。這是一種保護機制,是為了避免意外的調用Entry.objects.delete() 方法導致所有的記錄被誤刪除。如果你確認要刪除所有的對象,那么你必須顯示的調用:

Entry.objects.all().delete()

  如果不想級聯刪除,可以設置為:

pubHouse = models.ForeignKey(to='Publisher', on_delete=models.SET_NULL, blank=True, null=True)

  如果是多對多的關系:remove() 和 clear()方法

多對多刪除的兩個重要參數:clear()  清空數據      remove()   刪除數據

 

#正向
book = models.Book.objects.filter(id=1)

#刪除第三張表中和女孩1關聯的所有關聯信息
book.author.clear()        #清空與book中id=1 關聯的所有數據
book.author.remove(2)  #可以為id
book.author.remove(*[1,2,3,4])     #可以為列表,前面加*

#反向
author = models.Author.objects.filter(id=1)
author.book_set.clear() #清空與boy中id=1 關聯的所有數據

  

9,修改表記錄(update和save)

Book.objects.filter(title__startswith="py").update(price=120)

  此外,update() 方法對於任何結果集(QuerySet)均有效,這意味着你可以同時更新多條記錄update()方法會返回一個整型數值,表示受影響的記錄條數。

#---------------- update方法直接設定對應屬性----------------
    models.Book.objects.filter(id=3).update(title="PHP")
    ##sql:
    ##UPDATE "app01_book" SET "title" = 'PHP' WHERE "app01_book"."id" = 3; args=('PHP', 3)


#--------------- save方法會將所有屬性重新設定一遍,效率低-----------
    obj=models.Book.objects.filter(id=3)[0]
    obj.title="Python"
    obj.save()
# SELECT "app01_book"."id", "app01_book"."title", "app01_book"."price", 
# "app01_book"."color", "app01_book"."page_num", 
# "app01_book"."publisher_id" FROM "app01_book" WHERE "app01_book"."id" = 3 LIMIT 1; 
# 
# UPDATE "app01_book" SET "title" = 'Python', "price" = 3333, "color" = 'red', "page_num" = 556,
# "publisher_id" = 1 WHERE "app01_book"."id" = 3;

  在這個例子里我們可以看到Django的save()方法更新了不僅僅是title列的值,還有更新了所有的列。若title以外的列有可能會被其他的進程所改動的情況下,只更改title列顯然是更加明智的。更改某一指定的列,我們可以調用結果集(QuerySet)對象的update()方法,與之等同的SQL語句變得更加高效,並且不會引起競態條件。

  此外,update()方法對於任何結果集(QuerySet)均有效,這意味着你可以同時更新多條記錄update()方法會返回一個整型數值,表示受影響的記錄條數。

  注意:這里因為update返回的是一個整型,所以沒法用query屬性;對於每次創建一個對象,想顯示對應的raw sql ,需要在settings加上日志記錄部分:

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

  注意:如果是多對多的改:

    obj=Book.objects.filter(id=1)[0]
    author=Author.objects.filter(id__gt=2)

    obj.author.clear()
    obj.author.add(*author)

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM