Django入门   数据库的ORM操作之一对多

Django对数据库的是通过ORM实现。什么叫做ORM呢?简单来说,我们通过sql语句查询一张表的所有数据的语句如下  select * from test。而Django中用到的表都是在models.py文件里定义。所以我们要查查询test表里的数据可以通过

test_obj = models.test.objects.all()来获取test表里所有数据的对象。再通过

test_obj.values()方法将每一行数据的里的各个字段以key和value的字典形式读取出来。这就叫ORM操作。

既然涉及到数据库的操作,就必然会用到连表操作。ORM中将连表操作简单的划分为一对多 和多对多 这两种操作。

什么叫一对多呢?就是抽象的说法就是数据库的外键操作就是典型的一对多。数据库里的某一个字段可以对应另外一张表里的多个值。简单的举例的说法就是,一个管理员可以管理Host表里的多个主机。但是每一个主机只能对应一个管理员。这种情况就叫做一对多

1) 正向操作

首先我们先创建2张表。一张是主机表里面存放主机ip和端口信息。一张是管理员表,里面存放管理员姓名和管理的主机信息。那么我们的models.py里的代码如下:

# coding:utf-8
from __future__ import unicode_literals
from django.db import models
# Create your models here.
class host(models.Model):
    ip = models.CharField(max_length=32)
    port = models.IntegerField()
class hostadmin(models.Model):
    username = models.CharField(max_length=32)
    host = models.ForeignKey(‘host‘)

创建好表之后,我们给表里填充几行测试数据。

从有外键的表里查询关联表里的数据,这就叫正向操作。从我们的例子里可以看到外键定义在Hostadmin表里,那么我们从Hostadmin表里查询用户tom管理的所有的主机ip,这个需求就是正向查询。我们在views.py里的正向查询代码如下:

# coding:utf-8
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
def onetomany(request):
    # 通过filter方法匹配条件,将返回的对象存入ret_obj变量中
    ret_obj = models.hostadmin.objects.filter(username=‘tom‘)
    # 因为ret_obj是一个对象,这个对象是由数据库里的多行数据组成
    # 所以每循环一次item,这个item就代表一行包含所有字段的数据库数据
    for item in ret_obj:
        # ORM中跨表获取数据的操作用‘.‘来连接
        # item.host.ip表示通过HostAdmin表的host外键字段的值去获取对应的Host表里的ip字段
        # 注意数据库的表结构host外键字段被Django自动写成了host_id 
        # 但是使用ORM跨表操作的时候不可以使用host_id,还是应该使用models里定义的host这个字段名
        print item.host.ip
    return HttpResponse(‘ok‘)

运行结果,可以正确查询到tom名下所有的主机ip

再查询对ip为1.1.1.1的主机有管理权限的所有管理员名称,代码如下

# coding:utf-8
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
def onetomany(request):
    # 查询数据的时候通过‘__‘双下划线来进行跨表查询操作
    ret_obj = models.hostadmin.objects.filter(host__ip=‘1.1.1.1‘)
    for item in ret_obj:
        print item.username
    return HttpResponse(‘ok‘)

运行结果如下

以上的两种查询,我们都是通过对hostadmin表的操作实现的查询功能。至此正向查询就介绍完了。

2)反向操作

还是使用刚才的两张表,反向操作顾名思义就是通过不存在的外键的表反过来查询包含外键的表内数据。按照我们的例子就是通过Host表里的字段反过来查询Hostadmin表里的数据。

首先我们知道Host表与HostAdmin表是通过HostAdmin里面的host外键来建立联系的,做正向查询的时候通过host这个外键就可以查询到Host表里的数据。其实在这两个表创建联系的时候,Django在Host表里

也创建了一个隐藏的hostadmin字段来与HostAdmin表进行关联。那么如果我们要在Host表里查看tom用户所对应的所有ip的话,就可以利用Host表里的隐藏字段来关联用户名称。代码如下:

# coding:utf-8
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
def onetomany(request):
    # 利用Host表里隐藏的hostadmin字段关联查询HostAdmin表里的用户名称
    # 这种方式和正向查询很像
    ret_obj = models.host.objects.filter(hostadmin__username=‘tom‘)
    # 遍历查询的到的所有行
    for line in ret_obj:
        # 打印每一行的ip字段
        print line.ip
    return HttpResponse(‘ok‘)

运行结果,一样可以查出来对应的ip

如果我们希望通过Host表里的的ip为1.1.1.1的字段,反向查找到对应的管理员的名称。这个和正向查找的区别就比较大了。有以下2点需要注意

1、在Host表里必须通过get()方法精确的指定一行数据(不使用get()方法,就不能调用hostadmin_set反向获取数据)

2、获取的时候通过hostadmin_set.all()获取符合条件的所有HostAdmin表里的数据行的集合

功能实现的代码如下:

# coding:utf-8
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
def onetomany(request):
    # get()方法是只获取一行数据,如果获取不到就报错
    # 所以使用get方法的时候必须要确保可获取的条件
    host_obj = models.host.objects.get(ip=‘1.1.1.1‘)
    # 反向跨表通过hostadmin_set.all()才能获得关联表的所有数据行对象
    admin_obj = host_obj.hostadmin_set.all()
    # 打印获取到的对象
    print admin_obj
    # 遍历对象
    for line in admin_obj:
        #打印对象里的字段
        print line.username
    return HttpResponse(‘ok‘)

至此反向查询操作也介绍完了。

一对多的优化(select_related()方法)

我们还是以第一个正向查询作为例子讲解,代码如何下

# coding:utf-8
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
def onetomany(request):
    # 在HostAdmin表中查找所有符合条件的数据行
    ret_obj = models.hostadmin.objects.filter(username=‘tom‘)
    # 打印原始的sql语句
    print ret_obj.query
    for item in ret_obj:
        print item.host.ip
    return HttpResponse(‘ok‘)

获得原始sql代码如下:

上面这段代码的执行流程应该是这样子:

查找HostAdmin表里所有username=‘tom‘的数据行

-->查询出来之后获取这些数据行里的host_id的值

-->根据host_id的值到Host表里找到对应的ip

这个流程要要读取两次数据库才能获得Host和HostAdmin里的数据

下面我们优化一下,在models.hostadmin.objects.filter(username=‘tom‘)后面添加select_related()方法。

# coding:utf-8
from django.shortcuts import render,HttpResponse
from app01 import models
# Create your views here.
def onetomany(request):
    # 使用select_related()方法优化查询
    ret_obj = models.hostadmin.objects.filter(username=‘tom‘).select_related()
    # 打印原始的sql语句
    print ret_obj.query
    for item in ret_obj:
        print item.host.ip
    return HttpResponse(‘ok‘)

再来看看原始的SQL语句有什么不同

这次查询的时候直接通过join on语句把HostAdmin表里查询结果对应的Host表里的数据也给一并查询出来了。这样后面的item.ip需要用到Host表里数据的时候直接就可以在内存里获取到需要的数据,减少了一次对数据库的访问。

要注意:select_related()方法只能给一对多这种外键访问方式提供优化。多对多的操作没有作用。

一对多的简单总结

1、查询数据  也就是通过models.xxx.objects.filter()里填写查询条件的时候。这个时候获取的结果是一组数据行对象,不是具体的某个数据。跨表查询用到 对象名称__字段名(双下划线)

2、获取数据  也是具体到要获取某个字段的数据的时候。跨表操作通过‘.‘来连接各个表

3、反向查找的时候,查找的的表里会创建一个隐藏掉字段,这个字段名就是与创建外键的表同名

4、反向获取数据的时候,通过xxx_set.all()才能获取到   xxx所有被匹配到的对象

5、尽量用正向操作,反向的看着就麻烦。

双下划线的常用操作

# 增
    #
    # models.Tb1.objects.create(c1=‘xx‘, c2=‘oo‘)  增加一条数据,可以接受字典类型数据 **kwargs
    # obj = models.Tb1(c1=‘xx‘, c2=‘oo‘)
    # obj.save()
    # 查
    #
    # models.Tb1.objects.get(id=123)         # 获取单条数据,不存在则报错(不建议)
    # models.Tb1.objects.all()               # 获取全部
    # models.Tb1.objects.filter(name=‘seven‘) # 获取指定条件的数据
    # 删
    #
    # models.Tb1.objects.filter(name=‘seven‘).delete() # 删除指定条件的数据
    # 改
    # models.Tb1.objects.filter(name=‘seven‘).update(gender=‘0‘)  # 将指定条件的数据更新,均支持 **kwargs
    
    # obj = models.Tb1.objects.get(id=1)    # 修改单条数据
    # obj.c1 = ‘111‘
    # obj.save()                                                 
  
  
    # 获取个数
    #
    # models.Tb1.objects.filter(name=‘seven‘).count()
    # 大于,小于
    #
    # models.Tb1.objects.filter(id__gt=1)              # 获取id大于1的值
    # models.Tb1.objects.filter(id__lt=10)             # 获取id小于10的值
    # models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值
    # in
    #
    # models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
    # models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
    # contains
    #
    # models.Tb1.objects.filter(name__contains="ven")
    # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
    # models.Tb1.objects.exclude(name__icontains="ven")
    # range
    #
    # models.Tb1.objects.filter(id__range=[1, 2])   # 范围bettwen and
    # 其他类似
    #
    # startswith,istartswith, endswith, iendswith,
    # order by
    #
    # models.Tb1.objects.filter(name=‘seven‘).order_by(‘id‘)    # asc
    # models.Tb1.objects.filter(name=‘seven‘).order_by(‘-id‘)   # desc
    # limit 、offset
    #
    # models.Tb1.objects.all()[10:20]
    # group by
    from django.db.models import Count, Min, Max, Sum
    # models.Tb1.objects.filter(c1=1).values(‘id‘).annotate(c=Count(‘num‘))
    # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
时间: 2024-02-24 10:50:51

Django入门   数据库的ORM操作之一对多的相关文章

Django中的app及mysql数据库篇(ORM操作)

Django常见命令 在Django的使用过程中需要使用命令让Django进行一些操作,例如创建Django项目.启动Django程序.创建新的APP.数据库迁移等. 创建Django项目 一把我们都新建一个文件夹来存放项目文件,切换到这个目录下,启动命令行工具.创建一个名为mysite的Django项目: django-admin startproject mysite 创建好项目之后,可以查看当前目录下多出一个名为mysite的文件夹,mysite的文件夹目录结构如下: mysite/ ma

13.Django之数据库models&orm初探(一)

一.使用django orm的准备操作.django 默认支持sqlite,mysql, oracle,postgresql数据库.在默认情况下django的项目中会默认使用sqlite数据库,在打开settings里有如下设置: 当我们想改为mysql数据库时,需要在settings.py中做以下修改.DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'test_db', #数据库名称'USER': 'r

Django进阶(二)   数据库的ORM操作之多对多

多对多的关系简单来说就是两张表里的数据,每一行都可以对应另外一张表里的多行数据.采用我们在一对多时使用的例子.加入我们放开限制,主机表Host表的数据都有可以有多个管理员.同时反过来HostAdmin表里的每个管理员也同时管理多个主机.代码如下: # coding:utf-8 from __future__ import unicode_literals from django.db import models # Create your models here. class Host(mode

13.Django之数据库models&orm连表操作补充以及其他知识点补充(二)

一.外键关联. 假如说,现在有两张表,一张user表,这个表中存放了用户账户信息,还有一张usertype表,这张表存放了用户账户的类型. from django.db import models class UserType(models.Model): #用户类型表,虽然没有创建ID字段,但是ID字段会自动创建. type = models.CharField(max_length=32) class User(models.Model): #用户表 username = models.Ch

Django之模型层&ORM操作

一. 单表查询:  1.在模型层创建模型表: from django.db import models # Create your models here. # 单表查询表 class User(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() register_time = models.DateField()      2.连接MySQL,创建表 (具体操作见https://ww

Django之数据库连表操作

1.表结构修改 如果原来表中已存在的数据,表结构修改后就会出现结构混乱,makemigrations更新表的时候就会出错,解决方法: 1.新增加的字段,设置允许为空.生成表的时候,之前数据新增加的字段就会为空.(null=True允许数据库中为空,blank=True允许admin后台中为空)2.新增加的字段,设置一个默认值.生成表的时候,之前的数据新增加字段就会应用这个默认值 图片.IP字段 ip = models.GenericIPAddressField(protocol="ipv4&qu

django中数据库的相关操作

一.使用环境 python2.7,django>1.7 二.数据库进行配置 在setting文件中进行修改 1.找到DATABASES DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 'NAME': 'studentInfo', # Or path to database file if usi

数据库连表操作之一对多

引言 表:part 有表如上所示,当成员达到一定数量时,我们需要开启大量的空间存放他们所在的部分,部门名称又长,而且存在大量重复,十分浪费存储空间. 我们将表一分为二 表1:part 表2:person 何为一对多呢? 在part表中的一条数据对应person表中多条数据 表1:part  表2:person 设置外键 创建关联 创建约束:在part表中的一条数据对应person表中多条数据 CREATE TABLE person ( nid int(11) NOT NULL AUTO_INCR

Django的orm操作数据库

Django的orm操作数据库 django学习链接:https://www.cnblogs.com/clschao/articles/10526431.html 单表操作学习链接:https://www.cnblogs.com/clschao/articles/10427807.html about mvc或者mvc框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量,