天天看點

Django學習筆記:模型層之ORM

一、添加表記錄

# 方式一:
    book=Book(title="GO",price="99",pub_date="2018-12-31",publish="人民出版社")
    book.save()
    print(book.nid)  # 傳回值就是 Book 生成的對象

# 方式二:
    # 注意:create 方法的傳回目前生成的表記錄對象
    book = Book.objects.create(title="GO",price="99",pub_date="2018-12-31",publish="人民出版社")
           

注:關于create和save方法2種方式的不同,具體詳見原文連結:

https://blog.csdn.net/weixin_42134789/article/details/80203270

深入了解Django建立對象的create和save方法:

Django的模型(Model)的本質是類,并不是一個具體的對象(Object)。當你設計好模型後,你就可以對Model進行執行個體化進而建立一個一個具體的對象。Django對于建立對象提供了2種不同的save與create方法,我們來仔細分析下這兩種方式有什麼不同。

用save方法建立對象

用save方法建立一個名叫john的具體對象,我們可以這麼做。記住你隻有用了save()方法後,Django才會将這個對象的資訊存儲到資料庫中。

用create方法建立對象

正因為用save方法建立對象有2步,而且程式設計人員容易忘記加上save(),Django提供了一個更便捷的create方法,如下。如果你使用create方法,無需再加上save()。create方法不僅建立了新的對象,而且直接将資訊存儲到資料庫裡。

save與create方法比較:

create隻能用于建立新的對象,在資料庫層總是執行insert的操作。save不僅用于建立新的對象,也能用于更新對象的現有資料,在資料庫層總是先執行update,找不到具體對象後再執行insert的操作。對于建立全新的對象,兩者都可以。如果更新已有對象資訊,隻能用save()方法。

User自帶的create_user方法

如果你要Auth自帶的User模型建立新對象,你需要使用create_user方法,而不是create方法,如下所示。create_user方法很有用,自動會給密碼加Hash。

————————————————

版權聲明:本文為CSDN部落客「大江狗」的原創文章,遵循 CC 4.0 BY-SA 版權協定,轉載請附上原文出處連結及本聲明。

原文連結:https://blog.csdn.net/weixin_42134789/article/details/80203270

二 、查詢表記錄

1、查詢API:

all(): 查詢所有結果
filter(**kwargs): 包含了與所給篩選條件相比對的對象
get(**kwargs): 傳回與所給篩選條件相比對的對象,傳回結果有且隻有一個
exclude(**kwargs): 包含了與所給篩選條件不比對的對象
order_by(*field): 對查詢結果排序
reverse(): 對查詢結果反向排序
order_by(*field): 對查詢結果排序
count(): 傳回資料庫中比對查詢(QuerySet)的對象數量。
first(): 傳回第一條記錄
last(): 傳回最後一條記錄
exists(): 如果QuerySet包含資料,就傳回True,否則傳回False
distinct(): 從傳回結果中剔除重複記錄
"""以下示範單表查詢的代碼"""

    # 1、all(): 查詢所有結果 傳回值是 queryset
    ret = Book.objects.all()
    print(ret)  # <QuerySet [<Book: Book object (22)>, <Book: Book object (23)>, <Book: Book object (24)>, <Book: Book object (25)>]>

    # 2、filter(): 查詢包含了與所給篩選條件相比對的對象
    ret = Book.objects.filter(title="JAVA",price="88")  # 多條件查詢 當一個條件不滿足時,顯示為空- “且”的關系。<QuerySet []>
    print(ret)  # <QuerySet [<Book: Book object (23)>]>

    # 3、get(): # 查詢結果有且隻有一個才執行。
    ret = Book.objects.get(price="88")  # 報錯:get() returned more than one Book -- it returned 3! 如果符合篩選條件的對象超過一個或者沒有都會抛出錯誤。
    ret = Book.objects.get(title="JAVA")  # get() 傳回與所給篩選條件相比對的對象,傳回結果有且隻有一個
 	print(ret.title)  # JAVA

    # 4、first() last()  # 傳回第一條記錄 model對象
    ret = Book.objects.all()[0]
    ret = Book.objects.all().first()
    ret = Book.objects.all().last()

    # 5、exclude()  # 傳回值是 queryset
    ret = Book.objects.exclude(price=88)
    print(ret)  # <QuerySet [<Book: Book object (25)>]>

    # 6、order_by  # 排序,傳回值是 queryset
    ret = Book.objects.all().order_by("price")  # 按價格升序
    ret = Book.objects.all().order_by("-price")  # 按價格降序

    # 7、count()  # 計數,傳回資料庫中比對查詢(QuerySet)的對象數量。傳回值是 int 類型
    ret = Book.objects.all().count()
    print(ret)  # 4

    # 8、reverse()  # 對查詢結果反向排序
    Book.objects.all().order_by("price").reverse()

    # 9、exists()  # 邏輯判斷!如果QuerySet包含資料,就傳回True,否則傳回False
    is_exist = Book.objects.all().exists()  # b'SELECT (1) AS `a` FROM `app01_book`  LIMIT 1'; args=()
    if is_exist:
        print("OK")

    # ------------------------------------------------------------------------------------------------
    # 重點!!
    # 10、values()  # 傳回值是 queryset
    ret = Book.objects.all().values("title","price")   # 傳回一個ValueQuerySet——一個特殊的QuerySet 清單套字典 [{...}]
    print(ret)  # <QuerySet [{'title': 'python', 'price': Decimal('99.00')}, {'title': 'JAVA', 'price': Decimal('88.00')}, {'title': 'JavaScript', 'price': Decimal('88.00')}, {'title': 'GO', 'price': Decimal('66.00')}]>

    # 11、values_list()  # 傳回值是 queryset

    # 12、distinct()  # 從傳回結果中剔除重複記錄,傳回值是 queryset
    ret = Book.objects.all().distinct()  # 針對這種 all()再調用 distinct 沒有意義,因為對象包含了主鍵 nid,不可能重複!
    ret = Book.objects.all().values("title").distinct()  # 總共5本書,去重後結果是4本。配合比對 values 去重功能才會顯現
    print(ret)  # <QuerySet [{'title': 'python'}, {'title': 'JAVA'}, {'title': 'JavaScript'}, {'title': 'GO'}]>
           

2、基于雙下劃線的模糊查詢:

"""查詢價格"""
    ret = Book.objects.filter(price__in=[88,99]).values("price")  
    # 查詢價格區間在 88~99 的書籍
    ret = Book.objects.filter(price__lt=100).values("price")  
    # 查詢價格小于等于 100 的書籍
    ret = Book.objects.filter(price__gt=100).values("price")  
    # 查詢價格大于等于 100 的書籍
    ret = Book.objects.filter(price__gte=80).values("price")  
    # 查詢價格大于等于 88 的書籍
    
    """查詢名稱以 “J” 開頭的"""
    ret = Book.objects.filter(title__startswith="J").values("title")  
    # 查詢結果區分大小寫
    ret = Book.objects.filter(title__istartswith="j").values("title")  
    # 查詢結果不區分大小寫
    ret = Book.objects.filter(title__contains="S").values("title")  
    # 查詢結果隻要包含S的,區分大小寫
    ret = Book.objects.filter(title__icontains="S").values("title")  
    # 查詢結果不區分大小寫

    """查詢時間:2018年釋出的"""
    ret = Book.objects.filter(pub_date__year=2018).values("title")  
    # 僅查詢釋出年份
    ret = Book.objects.filter(pub_date__year=2018,pub_date__month=10).values("title")  
    # 查詢2018年10月釋出的
    print(ret)  
    # <QuerySet []> 輸出為空的原因:遇到時間偏差,因為時間子產品出問題,需要到 settings.py 中修改 :USE_TZ = True 改為 False
    #  <QuerySet [{'title': 'C++'}]>  這是修改以後的輸出,問題解決!
           

注意:

最後查詢年月列印輸出為空的原因:遇到時間偏差,因為時間子產品出問題,需要到 settings.py 中修改 :USE_TZ = True 改為 False

<QuerySet [{‘title’: ‘C++’}]> 這是修改以後的輸出,問題解決。

三、删除表記錄

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

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

示例:下面的代碼将删除 book_price 是 123 的 Book 對象:

# 以下2種寫法都可以
Book.objects.filter(price=123).delete()

Book.objects.filter(price=delete_book_price).delete()
           

四、修改表記錄

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

其實以上隻單純示範文法,它需要在浏覽器中輸入對應的值才能執行操作。相信沒有人願意這樣做。在下面的案例練習中會結合HTML頁面按鈕,來實作增、删、改、查的操作。

練習:圖書管理系統

urls.py:

from django.contrib import admin
from django.urls import path, re_path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', views.books, name="books"),
    path('books/add/', views.addbook),
    # re_path('books/delete/(\d+)', views.delbook, name="books"),  # 這裡僅用于删除!
    re_path('books/delete/(\d+)', views.delbook),  # name="books"是唯一的,就不能再用了!
    re_path('books/edit/(\d+)', views.editbook),
]
           

app01\views.py:

from django.shortcuts import render,HttpResponse,redirect
from app01.models import Book
from django.urls import reverse

def addbook(request):
	"""添加功能"""
    if request.method == "POST":
        # 擷取使用者送出的資料
        print(request.POST)
        # ---------------------------------------------------------------------------------------
        # 方式 1 :逐個取主鍵來建立資料,比較麻煩,特别是資料量大的情況下。
        title = request.POST.get("title")
        price = request.POST.get("price")
        pub_date = request.POST.get("pub_date")
        publish = request.POST.get("publish")
        book = Book.objects.create(title=title,price=price,pub_date=pub_date,publish=publish)
        # ---------------------------------------------------------------------------------------
        # 方式 2 :先轉成字典,再進行添加操作,相對于上面的方式1,友善許多!但是不直覺!
        # data = request.POST.dict()
        # del data["csrfmiddlewaretoken"]
        # book = Book.objects.create(**data)
        # ---------------------------------------------------------------------------------------
        return redirect(reverse("books"))
    else:
        return render(request,"addbook.html")

def books(request):
	"""查詢功能"""
    book_list = Book.objects.all() # 查所有
    # print(book_list) # [obj1, obj2, obj3...]
    # print(book_list[0].title)
    return render(request,"books.html",{"book_list":book_list})

def delbook(request,delete_book_id):
	"""删除功能"""
    Book.objects.filter(nid=delete_book_id).delete()
    return redirect(reverse("books"))

def editbook(request,edit_book_id):
    """修改功能"""
    # 以下2行代碼隻是示範了2種功能,查詢與編輯同時進行
    # Book.objects.filter(nid=edit_book_id).update(price=88,title="Django")  # 隻要輸入符合的ID,都會修改為:price=88,title="Django"
    # Book.objects.filter(price=88).update(publish="工業出版社")  # 隻要輸入符合的 price,都會修改為:publish="工業出版社"
    
    if request.method == "GET":  # GET請求
        edit_book = Book.objects.filter(nid=edit_book_id)[0]
        return render(request, "editbook.html",{"edit_book":edit_book})
        
    else:  # POST請求
        title = request.POST.get("title")
        price = request.POST.get("price")
        pub_date = request.POST.get("pub_date")
        publish = request.POST.get("publish")
        Book.objects.filter(nid=edit_book_id).update(title=title, price=price, pub_date=pub_date, publish=publish)

    return redirect("/books/")
           

models.py:

from django.db import models
# 存放表結構

class Book(models.Model):
    nid = models.AutoField(primary_key=True) #自動遞增主鍵
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2) #999999.99
    pub_date = models.DateTimeField() #"2019-10-01"
    publish = models.CharField(max_length=32)