Django中的ORM進階操作


Django中的ORM進階操作

 

Django中是通過ORM來操作數據庫的,通過ORM可以很easy的實現與數據庫的交互。但是仍然有幾種操作是非常繞也特別容易混淆的。於是,針對這一塊,來一個分類總結吧。

對於ORM對數據庫的基本操作前面model里已經有了介紹,這里專門針對ORM的一對多、多對多、正向、反向等操作來講解用法和注意事項。

 

銘記於心的兩條:

  • 在聯表操作過濾查找數據時用雙下划線 "__"
  • 取數據時用點 "."

 

一、一對多

  首先來設計兩張簡單的表格,並在其中一張表中設置一個另外一張表的外鍵值  

# --*-- coding:utf-8 -*-
from django.db import models


class UserType(models.Model):
    caption = models.CharField(max_length=32)


class UserInfo(models.Model):
    user_type = models.ForeignKey(UserType)
    username = models.CharField(max_length=32)
    age = models.IntegerField()

  

1、添加數據:


  傳id的方式:(字典的形式傳參)

user_dict = {"username": "chenchao", "age": "18", "user_type_id": 1}

models.UserInfo.objects.create(**user_dict)

  

  傳對象的方式:

user_type_obj = models.UserType.objects.get(id=1)   #先獲取外鍵表中的數據對象
user_dict = {"username": "chenchao", "age": "18", "user_type": user_type_obj}        #將對象傳入字典

models.UserInfo.objects.create(**user_dict)

講解:在我們寫的models類時,外鍵的字段是”user_type",而django在數據庫中保存字段時默認會在后面加“_id”,所以可以直接通過傳id的方式。

      而在表中的外鍵字段“user_type”又代表的是字典表中的一行數據對象。於是同樣可以傳對象的方式來傳參。

 

2、刪除數據

3、修改數據  (這兩個操作與上面的添加用法基本一致)

4、查找數據

   正向查找:(基於存在外鍵值表的查找為正向)

models.UserInfo.objects.filter(user_type__caption= "CEO")   #查找用戶類型為CEO的所有用戶, 雙下划線”__“

 

  反向查找:(基於不存在外鍵值表的查找為反向查找,前提是兩張表已經建立了關系)

  • 我們創建的外鍵表有兩個字段,id、caption。但Django默認在外鍵的表里還會埋藏一個字段為userinfo。可以get一個表中不存在的值,通過返回的報錯黃頁里面可以查看到。
  • 通過models獲取的值都是Qureyset。只要是這個類型就可以用.filter .all .count方法
  • 我們知道user_type_obj獲取的是外鍵表中的一行數據對象。
    • user_type_obj.id  代表一個數據
    • user_type_obj.caption  代表一個數據
    • user_type_obj.userinfo_set  特殊,代表的是一種能力。這個能力就可以獲取到這個用戶類型下的所有用戶或者某幾個用戶
    • request.user  代指的是django自帶的auth表里的一行數據,與userinfo做了一個OneToOne,與正向查詢是一樣的。所以也可以用request.user.userinfo.filter....

舉例:獲取某個人是什么用戶類型?當前用戶類型下有多少人?

user_type_obj = models.UserType.objects.get(userinfo__username= "chenchao")  #通過外鍵表來找到隱藏的userinfo字段下的username
user_type_obj.caption  # 獲取用戶chenchao的用戶類型
user_type_obj.userinfo_set.all().count()  #獲取此類型下的所有用戶個數

 

點贊的例子:

首先設計一下數據庫表結構,使點贊的一張表與用戶和文章建立外鍵關系

class MyUser(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=64)

    def __unicode__(self):
        return self.username


class News(models.Model):
    title = models.CharField(max_length=32)
    content = models.CharField(max_length=32)

    def __unicode__(self):
        return self.title


class Favor(models.Model):
    user_obj = models.ForeignKey(MyUser)
    new_obj = models.ForeignKey(News)

    def __unicode__(self):
        return "%s -> %s" %(self.user_obj.username, self.new_obj.title)
點贊表結構

通過反向來操作點贊表,獲取點贊的數量

def FoverNum(request):
    
    # 獲取所有文章的標題 內容和點贊數 
    # n_num = models.News.objects.all()   # 獲取所有新聞表的數據對象
    # for item in n_num:
    #     print items.title
    #     print items.content
    #     print item.favor_set.all().count()  
    
    # 獲取chenchao點過贊的所有的文章
    all_new = models.News.objects.filter(favor__user_obj__username="chenchao")  
    
    for items in all_new:
        print items.title
        print items.content
        print items.favor_set.all().count()

    return HttpResponse("Nothing")
操作表

 

二、多對多

首先設計好多對多的表結構:

class Host(models.Model):
    hostname = models.CharField(max_length=32)
    port = models.IntegerField()


class HostAdmin(models.Model):
    username = models.CharField(max_length=32)
    email = models.CharField(max_length=32)
    host = models.ManyToManyField(Host)

前兩張表通過models就可以創建,而第三張表django自動幫我們創建完成。我們主要針對第三張表,對其操作增刪改查。

 

1、增加數據

   正向添加基於存在外鍵值表的查找為正向): add

user_obj = models.HostAdmin.objects.get(username="chenchao")   # 獲取某個用戶的數據對象
host_obj = models.Host.objects.filter(id__lt=3)   # 獲取id小於3的主機數據對象
user_obj.host.add(*host_obj)   # 通過用戶對象下的ManyToMany的字段將主機與用戶的對象添加到第三張表中

  反向添加:(基於不存在外鍵值表的查找為反向查找,前提是兩張表已經建立了關系

host_obj = models.Host.objects.get(id=1)   # 1、獲取主機的數據對象
user_obj = models.HostAdmin.objects.filter(id__gt=1)   # 2、獲取用戶id大於1的數據對象
host_obj.hostadmin_set.add(*user_obj)      # 3、通過隱藏的外鍵字段hostadmin將主機對象與用戶對象添加到第三張表

 

2、查找數據

  正向查找:(基於存在外鍵值的表

user_obj = models.HostAdmin.objects.get(id=1)  # 獲取用戶的數據對象
print user_obj.host.all().count()              # 基於用戶對象,通過外鍵字段來查找第三張表中的個數

  反向查找:(基於不存在外鍵值的表

host_obj = models.Host.objects.get(id=1)       # 獲取主機的數據對象
print host_obj.hostadmin_set.all().count()     # 基於主機對象,通過隱藏的hostadmin_set字段來查找第三張中的數據

 

自定義Django的多對多的第三張表:

  django除了能自動創建多對多的第三張表,同樣也可以自定義創建多對多的第三張表,而且操作和管理擴展等難易程度要比自動創建的好許多。所以,在之后的models表結構中,推薦使用自定義的方式。

僅僅在創建時添加一個字段即可:through='HostRelation' 。   HostRelation是我們自定義的第三張表名。

class Host1(models.Model): hostname = models.CharField(max_length=32) port = models.IntegerField() 
class HostAdmin1(models.Model): username = models.CharField(max_length=32) email = models.CharField(max_length=32) host = models.ManyToManyField(Host1, through='HostRelation') class HostRelation(models.Model): #自定義創建第三張表,其中的外鍵都為一對多的關系 c1 = models.ForeignKey(Host1) c2 = models.ForeignKey(HostAdmin1)

 

1、創建數據

 操作自定義創建的多對多關系表的兩種方式:

def ManytoM(request): models.HostRelation.objects.create( # 傳對象的方式向第三張表中添加數據,笨法 c1=models.Host1.objects.get(id=1), c2=models.HostAdmin1.objects.get(id=2) ) models.HostRelation.objects.create(c1_id=2, c2_id=1,)  # 傳id的方式向第三張表中添加數據,easy idea
return HttpResponse("add_many to many OK")

 

 2、查找數據

relation_list = models.HostRelation.objects.all()  # 直接通過自定義的第三張表來查找數據

for item in relation_list:
    print item.c1.hostname    # 通過點”.“ 來獲取數據
    print item.c2.username

print models.HostRelation.objects.filter(c2__username="chenchao")   # 通過雙下划線”__“來查找數據

 

  

 三、select_related

select_related:用來優化數據庫查詢的操作,可以沒有,但優化的不夠徹底。

用於在foreignkey查詢的時候使用。可以通過query來查看一下django執行的sql語句。

ret1 = models.UserInfo.objects.all()
ret2 = models.UserInfo.objects.all().select_related()
print ret1.query            
print ret2.query            # 查看django執行的sql語句
ret1:

SELECT 
    "App01_userinfo"."id", 
    "App01_userinfo"."user_type_id", 
    "App01_userinfo"."username", 
    "App01_userinfo"."age" 

FROM "App01_userinfo" ret2:

SELECT 
    "App01_userinfo"."id", 
    "App01_userinfo"."user_type_id", 
    "App01_userinfo"."username", 
    "App01_userinfo"."age", 
    "App01_usertype"."id", 
    "App01_usertype"."caption" 
FROM 
    "App01_userinfo" INNER JOIN "App01_usertype" 
    
ON 
    ("App01_userinfo"."user_type_id" = "App01_usertype"."id")

 

 通過sql語句我們可以清晰地看到select_related不僅把當前表的內容查找出來,而且還把外鍵的表里的數據也查了出來。如果我們按ret1的方式,需要在多執行一次sql的查找操作。而ret2只需要執行一次。

 

 四、Django神奇的F

如果一張表中的數字列需要增加,那么F是最神奇的操作。

例如我們需要把user_info表里的所有age加1:

from django.db.models import F     #先要導入F

models.user_info.objects.all().update(age=F('age')+1)   #執行+1

 

五、Django更神奇的Q

 當做復雜的搜索查找條件時,django的Q可以提供非常便利的方法。

在設計搜索條件時,相同的字段為或操作(OR),不同的字段之間是且操作(AND)

from django.db.models import Q    # 導入Q
con = Q()   # 創建Q對象

q1 = Q()    
q1.connector = 'OR'      # q1的元素為OR或的關系
q1.children.append(('id', 1))
q1.children.append(('id', 10))
q1.children.append(('id', 9))

q2 = Q()
q2.connector = 'OR'      # q2的元素為OR或的關系
q2.children.append(('c1', 1))
q2.children.append(('c1', 10))
q2.children.append(('c1', 9))

con.add(q1, 'AND')      # 將q1添加到con對象中,與其他的Q為且的關系
con.add(q2, 'AND')

models.Tb1.objects.filter(con)   #將總的Q對象添加到model的查找條件中

提示:

1、之前所有的方法 如__gt,__lt,__contains. 雙下划線聯表查詢等等都可以繼續使用
2、append添加的是一個元組
3、最外層是用AND連接

 

             

 


免責聲明!

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



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