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 url from django.contrib import admin from app01 import views urlpatterns = [ 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,HttpResponse def 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 models def 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.query 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" ) |
所以说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_auth def 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)定义模型 模型,属性,表,字段间的关系 一 ...
随机推荐
- Nginx配置优化及深入讲解,大家可以听一下
随着访问量的不断增加,需要对Nginx和内核做相应的优化来满足高并发用户的访问,那下面在单台Nginx服务器来优化相关参数. 1) Nginx.conf配置优化: worker_proce ...
- 实战-Mysql5.6.36脚本编译安装及初始化
概述 本文为centos7.3自动化编译安装mysql5.3.6的脚本及后续初始化操作,话不多少,直接上脚本. 安装脚本install.py如下: #coding=utf-8 #!/usr/bin/p ...
- 开源API测试工具 Hitchhiker v0.6更新 - 改进压力测试
Hitchhiker 是一款开源的支持多人协作的 Restful Api 测试工具,支持Schedule, 数据对比,压力测试,支持上传脚本定制请求,可以轻松部署到本地,和你的team成员一起协作测试 ...
- Android开发之漫漫长途 Ⅷ——Android Binder(也许是最容易理解的)
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...
- ps的快捷键
最近学习了一些ps切图,总结一些快捷键,以免自己忘记,总结的不好,也可能不全,忘大牛指点,试着坚持总结 1.工具箱 (多种工具共用一个快捷键的可同时按[Shift]加此快捷键选取) 矩形.椭圆选框工具 ...
- LDA主题模型学习笔记5:C源代码理解
1.说明 本文对LDA原始论文的作者所提供的C代码中LDA的主要逻辑部分做凝视,原代码可在这里下载到:https://github.com/Blei-Lab/lda-c 这份代码实现论文<Lat ...
- hdu 5225 Tom and permutation(回溯)
题目链接:hdu 5225 Tom and permutation #include <cstdio> #include <cstring> #include <algo ...
- [基础规范]JavaBeans规范
本文来自维基百科:http://en.wikipedia.org/wiki/JavaBeans#JavaBean_conventions JavaBeans是Java语言中能够反复使用的软件组件,它们 ...
- mapreduce作业reduce被大量kill掉
之前有一段时间.我们的hadoop2.4集群压力非常大.导致提交的job出现大量的reduce被kill掉.同样的job执行时间比在hadoop0.20.203上面长了非常多.这个问题事实上是redu ...
- 知名互联网公司校招 Java 开发岗面试知识点解析
天之道,损有余而补不足,是故虚胜实,不足胜有余. 本文作者在一年之内参加过多场面试,应聘岗位均为 Java 开发方向.在不断的面试中,分类总结了 Java 开发岗位面试中的一些知识点. 主要包括以下几 ...