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举例说明
相关文章
相关标签/搜索