Django中的ORM進階操做

Django中的ORM進階操做

 

Django中是經過ORM來操做數據庫的,經過ORM能夠很easy的實現與數據庫的交互。可是仍然有幾種操做是很是繞也特別容易混淆的。因而,針對這一塊,來一個分類總結吧。python

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

 

銘記於心的兩條:數據庫

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

 

1、一對多

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

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

  

一、添加數據:app


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

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的方式。idea

      而在表中的外鍵字段「user_type」又表明的是字典表中的一行數據對象。因而一樣能夠傳對象的方式來傳參。spa

 

二、刪除數據設計

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

四、查找數據

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

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")
操做表

 

2、多對多

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

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自動幫咱們建立完成。咱們主要針對第三張表,對其操做增刪改查。

 

一、增長數據

   正向添加基於存在外鍵值表的查找爲正向): 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)   # 一、獲取主機的數據對象
user_obj = models.HostAdmin.objects.filter(id__gt=1)   # 二、獲取用戶id大於1的數據對象
host_obj.hostadmin_set.add(*user_obj)      # 三、經過隱藏的外鍵字段hostadmin將主機對象與用戶對象添加到第三張表

 

二、查找數據

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

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)

 

一、建立數據

 操做自定義建立的多對多關係表的兩種方式:

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

 

 二、查找數據

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")   # 經過雙下劃線」__「來查找數據

 

  

 3、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只須要執行一次。

 

 4、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

 

5、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的查找條件中

提示:

一、以前全部的方法 如__gt,__lt,__contains. 雙下劃線聯表查詢等等均可以繼續使用
二、append添加的是一個元組
三、最外層是用AND鏈接

相關文章
相關標籤/搜索