Django數據庫表結構設計多對多

from django.db import models

class UserInfo(models.Model):
    username = models.CharField(max_length=32)
    def __str__(self):
        return self.username

class UserGroup(models.Model):
    group_name = models.CharField(max_length=64)
    user_info = models.ManyToManyField(to='UserInfo',related_query_name='m2m')

    def __str__(self):
        return self.group_name

第一種:models.py 建立多對多表
from django.shortcuts import HttpResponse
from app01 import models

def orm(request):
    user_info_obj = models.UserInfo.objects.get(username='zhangsan')
    user_info_objs = models.UserInfo.objects.all()

    group_obj = models.UserGroup.objects.get(group_name='group_python')
    group_objs = models.UserGroup.objects.all()

    # 添加: 正向
    group_obj.user_info.add(user_info_obj)
    group_obj.user_info.add(*user_info_objs)
    # 刪除:正向
    group_obj.user_info.remove(user_info_obj)
    group_obj.user_info.remove(*user_info_objs)

    # 添加: 反向
    user_info_obj.usergroup_set.add(group_obj)
    user_info_obj.usergroup_set.add(*group_objs)
    # 刪除:反向
    user_info_obj.usergroup_set.remove(group_obj)
    user_info_obj.usergroup_set.remove(*group_objs)

    # 查找:正向
    print(group_obj.user_info.all())                                # 查找group_python組中全部用戶
    print(group_obj.user_info.all().filter(username='zhangsan'))
    # 查找:反向
    print(user_info_obj.usergroup_set.all())                        # 查找用戶zhangsan屬於那些組
    print(user_info_obj.usergroup_set.all().filter(group_name='group_python'))


    # 雙下劃線 正向、反向查找
    # 正向:從用戶組表中查找zhangsan屬於哪一個用戶組:[<UserGroup: group_python>]
    print( models.UserGroup.objects.filter(user_info__username='zhangsan'))

    # 反向:從用戶表中查詢group_python組中有哪些用戶:related_query_name='m2m'
    print( models.UserInfo.objects.filter(m2m__group_name='group_python'))


    # 自動建立UserInfo表和UserGroup表中的數據
    '''
    user_list = [{'username':'zhangsan'},
                {'username':'lisi'},
                {'username':'wangwu'},]
    group_list = [{'group_name':'group_python'},
               {'group_name':'group_linux'},
               {'group_name':'group_mysql'},]

    for c in user_list:
        models.UserInfo.objects.create(**c)

    for l in group_list:
        models.UserGroup.objects.create(**l)
    '''

    return HttpResponse('orm')

第一種:views.py 根據queryset對象增刪改查

第二種: 本身建立第三張關係表,無 m2m 字段,本身鏈表查詢html

from django.db import models

#表1:主機表
class Host(models.Model):
    nid = models.AutoField(primary_key=True)
    hostname = models.CharField(max_length=32,db_index=True)

#表2:應用表
class Application(models.Model):
    name = models.CharField(max_length=32)

#表3:自定義第三張關聯表
class HostToApp(models.Model):
    hobj = models.ForeignKey(to="Host",to_field="nid")
    aobj = models.ForeignKey(to='Application',to_field='id')

# 向第三張表插入數據,創建多對多外鍵關聯
HostToApp.objects.create(hobj_id=1,aobj_id=2)

第二種: 有第三張表,無m2m字段 models.py
from django.db import models

class Host(models.Model):
    hostname = models.CharField(max_length=32,db_index=True)

class Group(models.Model):
    group_name = models.CharField(max_length=32)
    m2m = models.ManyToManyField("Host")

第三種: models.py建立多對多表
from django.shortcuts import HttpResponse
from app01 import models

def orm(request):
    # 使用間接方法對第三張表操做
    obj = models.Group.objects.get(id=1)

    # 一、添加
    obj.m2m.add(1)           # 在第三張表中增長一個條目(1,1)
    obj.m2m.add(2, 3)        # 在第三張表中增長條目(1,2)(1,3)兩條關係
    obj.m2m.add(*[1,3])        # 在第三張表中增長條目(1,2)(1,3)兩條關係

    # 二、刪除
    obj.m2m.remove(1)             # 刪除第三張表中的(1,1)條目
    obj.m2m.remove(2, 3)          # 刪除第三張表中的(1,2)(1,3)條目
    obj.m2m.remove(*[1, 2, 3])    # 刪除第三張表中的(1,1)(1,2)(1,3)條目

    # 三、清空
    obj.m2m.clear()                 # 刪除第三張表中application條目等於1的全部條目

    # 4 更新
    obj.m2m.set([1, 2,])             # 第三張表中會刪除全部條目,而後建立(1,1)(1,2)條目

    # 5 查找
    print( obj.m2m.all() )           # 等價於 models.UserInfo.objects.all()

    # 6 反向查找: 雙下劃線
    hosts = models.Group.objects.filter(m2m__id=1)         # 在Host表中id=1的主機同時屬於那些組


    # 自動建立Host表和Group表中的數據
    '''
    hostname = [{'hostname':'zhangsan'},
                {'hostname':'lisi'},
                {'hostname':'wangwu'},]
    group_name = [{'group_name':'DBA'},{'group_name':'public'},]

    for h in hostname:
        models.Host.objects.create(**h)
    for u in group_name:
        models.Group.objects.create(**u)
    '''

    return HttpResponse('orm')

第三種:views.py 根據id增刪改查

 一大波Model操做 

from django.shortcuts import HttpResponse
from app01 import models

def orm(request):
    # 1 建立
    # 建立數據方法一
    models.UserInfo.objects.create(username='root', password='123')
    # 建立數據方法二
    obj = models.UserInfo(username='alex', password='123')
    obj.save()
    # 建立數據庫方法三(傳入字典必須在字典前加兩個星號)
    dic = {'username': 'eric', 'password': '666'}
    models.UserInfo.objects.create(**dic)

    # 2 查
    result = models.UserInfo.objects.all()  # 查找全部條目
    result = models.UserInfo.objects.filter(username='alex', password='123')
    for row in result:
        print(row.id, row.username, row.password)

    # 3 刪除
    models.UserInfo.objects.all().delete()  # 刪除全部
    models.UserInfo.objects.filter(username='alex').delete()  # 刪除指定

    # 4 更新
    models.UserInfo.objects.all().update(password='12345')
    models.UserInfo.objects.filter(id=4).update(password='15')

    # 5 獲取個數
    models.UserInfo.objects.filter(name='seven').count()

    # 6 執行原生SQL
    # 6.1 執行原生SQL
    models.UserInfo.objects.raw('select * from userinfo')

    # 6.2 若是SQL是其餘表時,必須將名字設置爲當前UserInfo對象的主鍵列名
    models.UserInfo.objects.raw('select id as nid from 其餘表')

    # 6.3 指定數據庫
    models.UserInfo.objects.raw('select * from userinfo', using="default")

    return HttpResponse('orm')

基本操做

 Model性能相關操做:select_related、prefetch_related

 

 

 一、普通查詢的缺點python

      1. 例:如今有兩張表user,和group兩張表,在user表中使用m做爲ForeignKey與group表進行一對多關聯mysql

      2. 若是經過user表中的實例查找對應的group表中的數據,就必須重複發sql請求linux

      3. prefetch_related()和select_related()的設計目,都是爲了減小SQL查詢的數量,可是實現的方式不同 sql

   二、select_related做用數據庫

      1. select_related主要針一對一和多對一關係進行優化。django

      2. select_related使用SQL的JOIN語句進行優化,經過減小SQL查詢的次數來進行優化、提升性能。app

  三、prefetch_related()做用性能

      1. prefetch_related()主要對於多對多字段和一對多字段進行優化fetch

      2. 進行兩次sql查詢,將查詢結果拼接成一張表放到內存中,再查詢就不用發sql請求

  四、select_related與prefetch_related 使用原則

      1. prefetch_related()和select_related()的設計目的很類似,都是爲了減小SQL查詢的數量,可是實現的方式不同

      2. 由於select_related()老是在單次SQL查詢中解決問題,而prefetch_related()會對每一個相關表進行SQL查詢,所以select_related()的效率高

      3. 因此儘量的用select_related()解決問題。只有在select_related()不能解決問題的時候再去想prefetch_related()。

def index(request):
    users = models.User.objects.filter(id__gt=30).prefetch_related('ut')
                       #ut和tu是user表的兩個foreign key,分別關聯不一樣的表

    users = models.User.objects.filter(id__gt=30).prefetch_related('ut','tu')
    #1 先執行第一次sql查詢:select * from users where id > 30;
    #2 好比:第一次查詢結果,獲取上一步驟中全部ut_id=[1,2]
    #3 而後執行第二次sql查詢:select * from user_type where id in [1,2]
    #4 這樣就僅執行了兩次sql查詢將兩個表的數據拼到一塊兒,放到內存中,再查詢就不用發sql請求
    for row in users:
        print(row.user,row.ut_id)       #這裏打印user表中的內容沒必要再次sql請求

prefetch_related舉例說明
def index(request):
    #1 這種方法低效
    users = models.User.objects.all()    #拿到的僅僅是user表中內容
    for row in users:
        print(row.user,row.ut_id)        #這裏打印user表中的內容沒必要再次sql請求
        print(row.ut.name)               #第一次查表,沒有拿到關聯表ut字段中的內容
                                         #因此每次循環都會再次發sql請求,拿到ut.name的值,低效

    #2 使用這種方法也僅須要一次數據庫查詢(拿到的是字典),可是若是查找的不在那些字段中直接報錯
    users = models.User.objects.all().values('user','pwd','ut__name')

    #3 select_related()能夠一次sql查詢拿到全部關聯表信息
    users = models.User.objects.all().select_related()
    
    # 這裏還支持指定只拿到那個關聯表的全部信息,好比:有多個外鍵關聯,只拿到與ut外鍵關聯的表
    users = models.User.objects.all().select_related('ut')


# select_related() 接受depth參數,depth參數能夠肯定select_related的深度。
# Django會遞歸遍歷指定深度內的全部的OneToOneField和ForeignKey。以本例說明:
# zhangs = Person.objects.select_related(depth = d)
# d=1  至關於 select_related(‘hometown’,'living’)
# d=2  至關於 select_related(‘hometown__province’,'living__province’)

select_related舉例說明
相關文章
相關標籤/搜索