Django ORM详解
ORM:(在django中,根据代码中的类自动生成数据库的表也叫--code first)
ORM:Object Relational Mapping(关系对象映射)
我们写的类表示数据库中的表
我们根据这个类创建的对象是数据库表里的一行数据
obj.id obj.name.....就是数据库一行数据中的一部分数据
ORM--First:
我们在学习django中的orm的时候,我们可以把一对多,多对多,分为正向和反向查找两种方式。
|
1
2
3
4
5
6
7
|
class UserType(models.Model): caption = models.CharField(max_length=32)class UserInfo(models.Model): username = models.CharField(max_length=32) age = models.IntegerField() user_type = models.ForeignKey('UserType')#外键 |
正向查找:ForeignKey在 UserInfo表中,如果从UserInfo表开始向其他的表进行查询,这个就是正向操作,反之如果从UserType表去查询其他的表这个就是反向操作。
马上就要开始我们的orm查询之旅!!!
建表+配置url+views中写相应的函数
models.py(在django中仅且只能在这里写数据库的相关类)
|
1
2
3
4
5
6
7
|
class UserType(models.Model): caption = models.CharField(max_length=32)class UserInfo(models.Model): username = models.CharField(max_length=32) age = models.IntegerField() user_type = models.ForeignKey('UserType') |
这里我们使用sqlite3数据库,在settings中使用默认设置就可以了
url.py中的配置
|
1
2
3
4
5
6
7
8
9
|
from django.conf.urls import urlfrom django.contrib import adminfrom app01 import viewsurlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^user_type',views.user_type), url(r'^user_info',views.user_info),] |
views.py先不进行任何操作,我们先保证正常访问已经设置的url
|
1
2
3
4
5
6
7
|
from django.shortcuts import render,HttpResponsedef user_type(req): return HttpResponse("ok")def user_info(req): return HttpResponse("ok") |
先在表中插入几个数据用于测试:
usertype表

userinfo表数据插入:
所以我们在创建UserType数据的时候有两种方法:第一种方法是直接根据这个字段进行添加数据!给user_type 加 '_id'
|
1
2
3
4
|
def user_info(request): dic = {'username':'mosson','age':18,'user_type_id':1} models.UserInfo.objects.create(**dic) return HttpResponse('OK') |
或者通过对象添加
|
1
2
3
4
5
6
7
|
#先获取组的对象usertype = models.UserType.objects.fiter(id=2)#添加的时候直接添加对象就可以models.UserInfo.objects.create(username='seven',age=18,user_type=usertype)#写成一行也行models.UserInfo.objects.create(username='lile',age=18,user_type=models.UserType.objects.filter(id=1)) |
django的get方法是从数据库的取得一个匹配的结果,返回一个对象,如果记录不存在的话,它会报错。
django的filter方法是从数据库的取得匹配的结果,返回一个对象列表,如果记录不存在的话,它会返回[]。

ORM的一对多:
我们在设计表结构的时候什么时候使用一对多呢?
比如我们在建立用户的时候有个菜单让我们选择用户类型的时候,使用一对多!!
1、一对多的正向查找:
正向查:ForeignKey在UserInfo表里,如果根据UserInfo这张表去查询这两张关联的表的合起来的内容就是正向查
反向查:ForeignKey不在UserType里,如果根据UserType这张表去查询这两张关联的表的合起来的内容就是反向查
正向查-demo1--查询所有用户为COO 的用户
在django中外键就相当于简单的使用__连表,在外键那个对象中封装了user_type表中的所有字段
我们要查询所有用户为CEO的用户,我们是不是的根据UserType这张表去查,如果是跨表查询使用“双下划线” + 属性
|
1
2
3
4
5
6
7
|
from app01 import modelsdef index(req): ret = models.UserInfo.objects.filter(user_type__caption='COO') print(ret) for item in ret: print(item,item.username,item.age,item.user_type.caption) return HttpResponse("OK") |
查询结果:

反向查询:--
我们可以根据下面的命令,取出一个用户组,那么对于这个用户组他有多少个用户呢?
|
1
|
models.UserType.objects.get(id=1) |
|
1
2
3
4
5
6
7
8
9
10
11
|
obj=models.UserType.objects.get(id=1) obj.caption====得到在UserType表中id为1对应的caption obj.id======得到在UserType表中id为1 obj.userinfo_set #理解为一种能力,可以获取所有当前这个用户类型的用户/或者这个用户类型的多个用户 obj.userinfo_set.all() #获取所有用户类型为COO的用户 obj.userinfo_set.filter(username='tim') #获取用户类型为COO的并且用户为tim的用户 ''' 这.userinfo_set.相当于什么?它相当于 models.UserInfo.objects.filter(user_type=obj) ''' |
反向查询实例:查询COO用户下的所有的用户名
|
1
2
3
|
ret = models.UserType.objects.filter(caption='COO').values('userinfo__username') for item in ret: print(item,type(item)) |
方法二、
|
1
2
3
4
|
ret = models.UserType.objects.filter(caption='COO').first() for item in ret.userinfo_set.all(): print(item.username) |
总结:
正向查找:
filter(跨表的时候,应该是对象__跨表的字段)
获取这个值的时候,拿到了一行数据的时候 line.对象.跨表的字段
反向查找:
filter(关联这个表的表明) 自动创建和表明相同的对象,通过这个对象__跨表的字段
line.自动创建和表明相同的对象_set.方法

ORM多对多 系统生成第三张表:
多对多和一对多没有任何关系
models.py
|
1
2
3
4
5
6
7
8
|
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') |
当我们在host表里和hostadmin表里添加数据时和第三章关系表没有任何关系,当我们这样去建立表时,第三张表里面的列就已经固定了,分别是这两个表的id
给主机表添加数据:
|
1
2
3
4
5
6
7
8
9
10
11
|
def index(req): #主机数据 models.Host.objects.create(hostname='host1.test.com', port=80) models.Host.objects.create(hostname='host2.test.com', port=80) models.Host.objects.create(hostname='host3.test.com', port=80) models.Host.objects.create(hostname='host4.test.com', port=80) #用户数据 models.HostAdmin.objects.create(username='alex', email='alex@qq.com') models.HostAdmin.objects.create(username='mosson', email='mosson@qq.com') models.HostAdmin.objects.create(username='aliven', email='aliven@qq.com') models.HostAdmin.objects.create(username='wusir', email='wusir@qq.com') |
数据中的效果:


空的关系表

多对多正向、反向添加数据

正向添加数据:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
def index(request): #正向添加数据 #找到用户dali这个 admin_obj = models.HostAdmin.objects.get(username='dali') #找到主机 host_list = models.Host.objects.filter(id__lt=3) #通过找到的dali的对象.add去添加数据 admin_obj.host.add(*host_list) ''' admin_obj 通过大力这个对象.add 去操作的主机, 大力的ID为 2 主机ID为:(1,2) 那就会生成这样的表: #2 1 #2 2 ''' return HttpResponse('OK') |
反向添加数据:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
def index(request): #反向添加数据 #获取主机 host_obj = models.Host.objects.get(id=3) #获取用户列表 admin_list = models.HostAdmin.objects.filter(id__gt=1) #和一对多一样的道理 host_obj.hostadmin_set.add(*admin_list) #host_obj = 3 管理员ID = 2 3 4 #3 2 #3 3 #3 4 return HttpResponse('OK') |
ORM 多对多 自定义 第三张表
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
class HostInfo(models.Model): hostname = models.CharField(max_length=32) port = models.IntegerField()class UserMap(models.Model): username = models.CharField(max_length=32) email = models.CharField(max_length=32) #through告诉Django用那张表做关联 host = models.ManyToManyField(HostInfo , through='HostRelation')class HostRelation(models.Model): host = models.ForeignKey('HostInfo') user = models.ForeignKey('UserMap') ''' 并且这里我们可以添加多个关系,比如在加一个字段 usertype = models.ForeignKey('UserType') 或者增加一个普通字段 status = models.CharField(max_length=32) ''' |
现在咱们自己创建了第三张表了。现在我们已经会了两种方式创建第三张表了,当我们使用自定义创建的第三张表的时候,在去添加数据的时候!
就不能使用第一种方式对象添加了!
现在我们有第三张表了这个对象了,我们就不需要管另外两张表了,直接添加就行了! 0 0 !
添加主机和用户--
|
1
2
3
4
5
6
7
8
9
10
11
|
def index(req): models.HostInfo.objects.create(hostname='alex.test.com', port=80) models.HostInfo.objects.create(hostname='seven.test.com', port=80) models.HostInfo.objects.create(hostname='mosson.test.com', port=80) models.UserMap.objects.create(username='alex', email='alex@qq.com') models.UserMap.objects.create(username='seven', email='seven@qq.com') models.UserMap.objects.create(username='mosson', email='mosson@qq.com') return HttpResponse('ok') |
将数据插入到第三张表中---办法1:
插入单条数据
|
1
2
3
4
5
6
|
def index(request): models.HostRelation.objects.create( user = models.UserMap.objects.get(id=1), host = models.HostInfo.objects.get(id=1) ) return HttpResponse('OK') |
多对多两种方式对比和查询

查询--方法一:
第一种方式都是基于表中的对象去找到第三张表! 通过间接的方式找到这张表的句柄!
|
1
2
3
4
5
6
|
#正向查admin_obj = models.HostAdmin.objects.get(id=1)admin_obj.host.all()#反相差host_obj = models.Host.objects.get(id=1)host_obj.hostadmin_set.all() |
查询--方法二:
用第二种方法就没有正向和反向这么一说了,直接查即可!
|
1
2
3
4
|
relation_list = models.HostRelation.objects.all()for item in relation_list: #每一个item就是一个关系 print (item.user.username) print( item.host.hostname) |
|
1
2
3
4
|
relation_list = models.HostRelation.objects.filter(user__username='mosson') for item in relation_list: #每一个item就是一个关系 print( item.user.username) print (item.host.hostname) |
通过第二种方式可以把所有的关系都找到,第一种方式可以把所有的关系表都找到吗?
第一种方式只能找到某一个人管理的机器,不能把有的对应关系找到!
select_related的作用:
|
1
2
3
4
5
6
7
|
class UserType(models.Model): caption = models.CharField(max_length=32)class UserInfo(models.Model): user_type = models.ForeignKey('UserType') #这个user_type是一个对象,对象里面封装了ID和caption username = models.CharField(max_length=32) age = models.IntegerField() |
select_related的作用,他就是用来优化查询的,没有他也可以,用它主要是用来优化ForeignKey
|
1
2
3
4
5
6
7
|
def index(request): ret = models.UserInfo.objects.all() #咱们看下他执行的什么SQL语句 print( ret.query)'''SELECT "app01_userinfo"."id", "app01_userinfo"."user_type_id", "app01_userinfo"."username", "app01_userinfo"."age" FROM "app01_userinfo"''' |
加上select_related是什么样子的
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
def user_info(request): ret = models.UserInfo.objects.all().select_related() #咱们看下他执行的什么SQL语句 print ret.querySELECT "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") |
所以说select_related就是优化查询的!
ORM连表操作的梳理:
一、一对多创建
1、创建数据
通过对象创建
或者通过对象字段_id创建
2、查找
正向查找
在通过filter的时候跨表使用 双下划线 '__'
在获取值得时候通过.跨表
反向查找
Django自动生成 表名_set
其他操作和正向查找一样
二、多对对
1、自动生成关系表
间接的方式获取关系表,如果是正向的:一行数据的对象.ManyToMany字典就行 反向:一行数据的对象.表名_set
2、自定义关系表(推荐)不管是添加、修改只对关系表操作就行
三、select_related
用于优化查询,一次性将查询的表和ForiegnKey关联的表一次性加载到内存。
Django中的F和Q
F:用来批量修改数据(使用查询条件的值)
demo:比如我有个price这个列,我想让price自增10或者某一些自增10
|
1
2
|
# from django.db.models import F# models.Tb1.objects.update(num=F('num')+10) |
Q:用来做条件查询的
默认的django的查询只是且操作如下:
|
1
|
models.UserInfo.objects.filter(username='mosson',age='18') |
找到用户名为:mosson且age=18的数据
有没有这么一种情况:username=mosson或 username=wusir 或 username=alex 并且 age=18的需求?原生的查询是不支持的!所以就用到了Q~
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
第一步:#生成一个搜索对象search_q = Q()#在生成两个搜索对象search1 = Q()search2 = Q()第二步:#标记search1中的搜索条件为 ‘ 或’ 查询search1.connector = 'OR'#把搜索条件加入到search1中search1.children.append(('字段名','字段内容'))search1.children.append(('字段名','字段内容'))search1.children.append(('字段名','字段内容'))search1.children.append(('字段名','字段内容'))#标记search2中的搜索条件为 ‘ 或’ 查询search2.connector = 'OR'#把搜索条件加入到search2中search2.children.append(('字段名','字段内容'))search2.children.append(('字段名','字段内容'))search2.children.append(('字段名','字段内容'))search2.children.append(('字段名','字段内容'))第三步:#把多个搜索条件进行合并search_q.add(search1,'AND')search_q.add(search2,'AND')第四步:#执行搜索models.HostInfo.objects.filter(search_q) |
实例:
在前端获取搜索条件的时候我把相同类型的搜索写成字典的形式{字段名:[条件结合列表]},这样我在查询的时候直接通过循环字典就可以把搜索条件分为不同的子条件!
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
function SearchSubmit() { //清空当前列表 $('#table-body').children().remove(); //设置一个空字典 SEARCH_DIC = {}; //找到所有的搜索框体 var search_data = $('.inputs').find("input[is-condition='true']"); //循环找到的内容 $.each(search_data,function (index,data) { //获取搜索的类型 /* 这里需要注意:重点::::: 这里和Django的Q可以进行耦合,在我们定义搜索的类型的时候可以直接写成我们要搜索的的'库中的字段或者条件都可以!!!' 如下: <input is-condition="true" type="text" placeholder="逗号分割多条件" class="form-control no-radius" name="hostname" /> */ var search_name = $(this).attr('name'); //获取搜索的值 var search_value = $(this).val(); if(SEARCH_DIC.hasOwnProperty(search_name)){//判断是否有这个KEY SEARCH_DIC[search_name].push(search_value) }else{ SEARCH_DIC[search_name] = [search_value] } } );//ajax请求结束 $.get("{% url 'search_info' %}",{'search_list':JSON.stringify(SEARCH_DIC)},function(callback){ $('#table-body').append(callback) });//搜索按钮结束 |
重点:
在前端我们定义input的name属性的时候,我们可以直接定义为数据库中的“字段名”,并且在Django的Q中支持跨表操作“双下划线”,所以我们在定义name的时候可以直接定义双下划线操作
|
1
|
search1.children.append(('字段名'__'跨表字段名','跨表字段内容')) |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
@login_authdef search_info(request): #获取用户请求的数据 user_post = json.loads(request.GET['search_list']) print user_post #生成搜索对象 Serach_Q = Q() #循环字典并生成搜索条件集合 for k,v in user_post.items(): #生成一个搜索结合 q = Q() #生命集合中的搜索条件为'或'条件 q.connector = 'OR' #循环字典中的value,value是前端传过来的条件集合 for i in v: #在搜索条件集合中增加条件,条件为元组形式,k为字典中的key! key是字段名或者跨表字段名或者支持_gt等 #i为字典中的vlaue中的元素,为条件 # q.children.append((k,i)) #没循环一次后后,吧他加入到总的搜索条件中 Serach_Q.add(q,'AND') #使用总的搜索条件进行查询 data = models.HostInfo.objects.filter(Serach_Q) #拼接字符串并返回 html = [] for i in data: html.append( "<tr>"+ "<td>" + "<input type='checkbox' >"+ "</td>" + "<td name='host_id'>" + '%s' %i.id + "</td>" + "<td name='host_name' edit='true'>" + i.hostname + "</td>"+ "<td name='host_ip' edit='true'>" + i.hostip + "</td>"+ "<td name='host_port' edit='true'>" + '%s' %i.hostport + "</td>"+ "<td name='host_business' edit='true' edit-type='select' global-key='BUSINESS' select-val='" + '%s' %i.hostbusiness_id + "'>" + i.hostbusiness.hostbusiness + "</td>"+ "<td name='host_status' edit='true' edit-type='select' global-key='STATUS' select-val='" + '%s' %i.hoststatus_id + "'>" + i.hoststatus.hoststatus + "</td>"+ "</tr>" ) html = mark_safe("".join(html)) return HttpResponse(html) |
Django ORM详解的更多相关文章
- Python之路【第二十一篇】Django ORM详解
ORM回顾 关系对象映射(Object Relational Mapping,简称ORM). django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表. 对于ORM框 ...
- Python全栈之路--Django ORM详解
ORM:(在django中,根据代码中的类自动生成数据库的表也叫--code first) ORM:Object Relational Mapping(关系对象映射) 我们写的类表示数据库中的表 我们 ...
- ORM详解
讲解对象:ORM详解 作者:融水公子 rsgz 1 前言:开发流程正常只有简单的几步 0.1 配置数据库 0.2 定义模型 0.3 迁移文件 0.4 执行迁移生成数据表 0.5 使用模型类增删改查 2 ...
- Django -- settings 详解
Django settings详解 1.基础 DJANGO_SETTING_MODULE环境变量:让settings模块被包含到python可以找到的目录下,开发情况下不需要,我们通常会在当前文件夹运 ...
- Django -- settings 详解(转)
Django -- settings 详解 Django settings详解 1.基础 DJANGO_SETTING_MODULE环境变量:让settings模块被包含到python可以找到的目 ...
- Django 2.0 学习(20):Django 中间件详解
Django 中间件详解 Django中间件 在Django中,中间件(middleware)其实就是一个类,在请求到来和结束后,Django会根据自己的规则在合适的时机执行中间件中相应的方法. 1. ...
- Django中间件详解
Django中间件详解 中间件位置 WSGI 主要负责的就是负责和浏览器和应用之家沟通的桥梁 浏览器发送过来一个http请求,WSGI负责解包,并封装成能够给APP使用的environ,当app数据返 ...
- 2018.10.7 理解Hibernate的工作原理及其中的ORM详解
复习 hibernate框架 简介j及其搭建: hibernate是一个开源框架,它是对象关联关系映射的框架,它对JDBC做了轻量级的封装,而我们java程序员可以使用面向对象的思想来操纵数据库. 1 ...
- django模型详解(四)
1 概述 (1)概述 : Django对各种数据库提供了很好的支持,Django为这些数据库提供了统一的调用API,根据不同的业务需求选择不同的数据库 (2)定义模型 模型,属性,表,字段间的关系 一 ...
随机推荐
- iOS 视频播放方式整理
初衷 多媒体这整个系列的文章自己也准备好开始整理了,先从视频音频最简单也是最常用的播放出发慢慢的往下深究,探索到底层的编码解码等等,这篇文章就从视频的播放这个最简单的说起. iOS的视频播放方式有几种 ...
- CCF-201509-1-数列分段
问题描述 试题编号: 201509-1 试题名称: 数列分段 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 给定一个整数数列,数列中连续相同的最长整数序列算成一段,问数列中共 ...
- Android崩溃提示 “EGL_BAD_CONFIG"
这两天将之前提到的一个室内定位程序的ArcGIS的SDK从10.2.8迁移到100.1.0. 期间反复出现奇怪的问题,最终定位到这个问题: java.lang.RuntimeException: cr ...
- 关于sqlmap使用手册
sqlmap 使用手册 官方wiki Github sqlmap也是渗透中常用的一个注入工具,可以用来检测sql注入漏洞. 功能与作用 完全支持MySQL,Oracle,PostgreSQL,Micr ...
- js模拟静态方法
//模拟静态 var Animal = function(name){ this.name = name; Animal.instanceCounter ++; }; Animal.instanceC ...
- 【C语言】统计数组中出现次数超过一半的数字
//统计数组中出现次数超过一半的数字 #include <stdio.h> int Find(int *arr, int len) { int num = 0; //当前数字 int ti ...
- Ration Rose2003安装及破解
曾经学习UML的时候,用的是EA. 近期在看Head First想着画绘图装一下Ration Rose吧.于是就着手開始装.本来网上关于Ration Rose的安装及破解教程非常多,可是我在安装的过程 ...
- JAVA入门[21]-Jedis操作redis示例
本节目标 通过JedisPool获取Jedis示例,并完成对redis 简单的Key-value读写操作. 完整代码结构如下: redis服务端 在本地运行redis-server.exe,然后在re ...
- Vue-Methods中使用Filter
1.Vue中Filter声明方式 Vue中存在两种声明Filter过滤器的方式: 1.全局过滤器 Vue.filter('testFilter1',function(val){ console.log ...
- FileSystemWatcher类监控文件的更改状态并且实时备份文件
首先这是我自己在一个任务需求里面所要用到的,大致的代码如下:我把监视文件和备份文件的方法封装到一个WatcherAndBackup 类中了,但是总感觉封装的不是很好,有大牛能够指出改正之处在此留言,谢 ...