Django中的ORM进阶操作
Django中的ORM进阶操作
Django中是通过ORM来操作数据库的,通过ORM可以很easy的实现与数据库的交互。但是仍然有几种操作是非常绕也特别容易混淆的。于是,针对这一块,来一个分类总结吧。
对于ORM对数据库的基本操作前面model里已经有了介绍,这里专门针对ORM的一对多、多对多、正向、反向等操作来讲解用法和注意事项。
铭记于心的两条:
- 在联表操作过滤查找数据时用双下划线 "__"
- 在取数据时用点 "."
一、一对多
首先来设计两张简单的表格,并在其中一张表中设置一个另外一张表的外键值
# --*-- coding:utf-8 -*-
from django.db import models class UserType(models.Model):
caption = models.CharField(max_length=32) class UserInfo(models.Model):
user_type = models.ForeignKey(UserType)
username = models.CharField(max_length=32)
age = models.IntegerField()
1、添加数据:
传id的方式:(字典的形式传参)
user_dict = {"username": "chenchao", "age": "18", "user_type_id": 1} models.UserInfo.objects.create(**user_dict)
传对象的方式:
user_type_obj = models.UserType.objects.get(id=1) #先获取外键表中的数据对象
user_dict = {"username": "chenchao", "age": "18", "user_type": user_type_obj} #将对象传入字典 models.UserInfo.objects.create(**user_dict)
讲解:在我们写的models类时,外键的字段是”user_type",而django在数据库中保存字段时默认会在后面加“_id”,所以可以直接通过传id的方式。
而在表中的外键字段“user_type”又代表的是字典表中的一行数据对象。于是同样可以传对象的方式来传参。
2、删除数据
3、修改数据 (这两个操作与上面的添加用法基本一致)
4、查找数据
正向查找:(基于存在外键值表的查找为正向)
models.UserInfo.objects.filter(user_type__caption= "CEO") #查找用户类型为CEO的所有用户, 双下划线”__“
反向查找:(基于不存在外键值表的查找为反向查找,前提是两张表已经建立了关系)
- 我们创建的外键表有两个字段,id、caption。但Django默认在外键的表里还会埋藏一个字段为userinfo。可以get一个表中不存在的值,通过返回的报错黄页里面可以查看到。
- 通过models获取的值都是Qureyset。只要是这个类型就可以用.filter .all .count方法
- 我们知道user_type_obj获取的是外键表中的一行数据对象。
- user_type_obj.id 代表一个数据
- user_type_obj.caption 代表一个数据
- user_type_obj.userinfo_set 特殊,代表的是一种能力。这个能力就可以获取到这个用户类型下的所有用户或者某几个用户
- request.user 代指的是django自带的auth表里的一行数据,与userinfo做了一个OneToOne,与正向查询是一样的。所以也可以用request.user.userinfo.filter....
举例:获取某个人是什么用户类型?当前用户类型下有多少人?
user_type_obj = models.UserType.objects.get(userinfo__username= "chenchao") #通过外键表来找到隐藏的userinfo字段下的username
user_type_obj.caption # 获取用户chenchao的用户类型
user_type_obj.userinfo_set.all().count() #获取此类型下的所有用户个数
点赞的例子:
首先设计一下数据库表结构,使点赞的一张表与用户和文章建立外键关系
class MyUser(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=64) def __unicode__(self):
return self.username class News(models.Model):
title = models.CharField(max_length=32)
content = models.CharField(max_length=32) def __unicode__(self):
return self.title class Favor(models.Model):
user_obj = models.ForeignKey(MyUser)
new_obj = models.ForeignKey(News) def __unicode__(self):
return "%s -> %s" %(self.user_obj.username, self.new_obj.title)
点赞表结构
通过反向来操作点赞表,获取点赞的数量
def FoverNum(request): # 获取所有文章的标题 内容和点赞数
# n_num = models.News.objects.all() # 获取所有新闻表的数据对象
# for item in n_num:
# print items.title
# print items.content
# print item.favor_set.all().count() # 获取chenchao点过赞的所有的文章
all_new = models.News.objects.filter(favor__user_obj__username="chenchao") for items in all_new:
print items.title
print items.content
print items.favor_set.all().count() return HttpResponse("Nothing")
操作表
二、多对多
首先设计好多对多的表结构:
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)
前两张表通过models就可以创建,而第三张表django自动帮我们创建完成。我们主要针对第三张表,对其操作增删改查。
1、增加数据
正向添加(基于存在外键值表的查找为正向): add
user_obj = models.HostAdmin.objects.get(username="chenchao") # 获取某个用户的数据对象
host_obj = models.Host.objects.filter(id__lt=3) # 获取id小于3的主机数据对象
user_obj.host.add(*host_obj) # 通过用户对象下的ManyToMany的字段将主机与用户的对象添加到第三张表中
反向添加:(基于不存在外键值表的查找为反向查找,前提是两张表已经建立了关系)
host_obj = models.Host.objects.get(id=1) # 1、获取主机的数据对象
user_obj = models.HostAdmin.objects.filter(id__gt=1) # 2、获取用户id大于1的数据对象
host_obj.hostadmin_set.add(*user_obj) # 3、通过隐藏的外键字段hostadmin将主机对象与用户对象添加到第三张表
2、查找数据
正向查找:(基于存在外键值的表)
user_obj = models.HostAdmin.objects.get(id=1) # 获取用户的数据对象
print user_obj.host.all().count() # 基于用户对象,通过外键字段来查找第三张表中的个数
反向查找:(基于不存在外键值的表)
host_obj = models.Host.objects.get(id=1) # 获取主机的数据对象
print host_obj.hostadmin_set.all().count() # 基于主机对象,通过隐藏的hostadmin_set字段来查找第三张中的数据
自定义Django的多对多的第三张表:
django除了能自动创建多对多的第三张表,同样也可以自定义创建多对多的第三张表,而且操作和管理扩展等难易程度要比自动创建的好许多。所以,在之后的models表结构中,推荐使用自定义的方式。
仅仅在创建时添加一个字段即可:through='HostRelation' 。 HostRelation是我们自定义的第三张表名。
class Host1(models.Model):
hostname = models.CharField(max_length=32)
port = models.IntegerField()
class HostAdmin1(models.Model):
username = models.CharField(max_length=32)
email = models.CharField(max_length=32)
host = models.ManyToManyField(Host1, through='HostRelation') class HostRelation(models.Model): #自定义创建第三张表,其中的外键都为一对多的关系
c1 = models.ForeignKey(Host1)
c2 = models.ForeignKey(HostAdmin1)
1、创建数据
操作自定义创建的多对多关系表的两种方式:
def ManytoM(request): models.HostRelation.objects.create( # 传对象的方式向第三张表中添加数据,笨法
c1=models.Host1.objects.get(id=1),
c2=models.HostAdmin1.objects.get(id=2)
)
models.HostRelation.objects.create(c1_id=2, c2_id=1,) # 传id的方式向第三张表中添加数据,easy idea
return HttpResponse("add_many to many OK")
2、查找数据
relation_list = models.HostRelation.objects.all() # 直接通过自定义的第三张表来查找数据 for item in relation_list:
print item.c1.hostname # 通过点”.“ 来获取数据
print item.c2.username print models.HostRelation.objects.filter(c2__username="chenchao") # 通过双下划线”__“来查找数据
三、select_related
select_related:用来优化数据库查询的操作,可以没有,但优化的不够彻底。
用于在foreignkey查询的时候使用。可以通过query来查看一下django执行的sql语句。
ret1 = models.UserInfo.objects.all()
ret2 = models.UserInfo.objects.all().select_related()
print ret1.query
print ret2.query # 查看django执行的sql语句
ret1: SELECT
"App01_userinfo"."id",
"App01_userinfo"."user_type_id",
"App01_userinfo"."username",
"App01_userinfo"."age" FROM "App01_userinfo" ret2: 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")
通过sql语句我们可以清晰地看到select_related不仅把当前表的内容查找出来,而且还把外键的表里的数据也查了出来。如果我们按ret1的方式,需要在多执行一次sql的查找操作。而ret2只需要执行一次。
四、Django神奇的F
如果一张表中的数字列需要增加,那么F是最神奇的操作。
例如我们需要把user_info表里的所有age加1:
from django.db.models import F #先要导入F models.user_info.objects.all().update(age=F('age')+1) #执行+1
五、Django更神奇的Q
当做复杂的搜索查找条件时,django的Q可以提供非常便利的方法。
在设计搜索条件时,相同的字段为或操作(OR),不同的字段之间是且操作(AND)
from django.db.models import Q # 导入Q
con = Q() # 创建Q对象 q1 = Q()
q1.connector = 'OR' # q1的元素为OR或的关系
q1.children.append(('id', 1))
q1.children.append(('id', 10))
q1.children.append(('id', 9)) q2 = Q()
q2.connector = 'OR' # q2的元素为OR或的关系
q2.children.append(('c1', 1))
q2.children.append(('c1', 10))
q2.children.append(('c1', 9)) con.add(q1, 'AND') # 将q1添加到con对象中,与其他的Q为且的关系
con.add(q2, 'AND') models.Tb1.objects.filter(con) #将总的Q对象添加到model的查找条件中
提示:
1、之前所有的方法 如__gt,__lt,__contains. 双下划线联表查询等等都可以继续使用
2、append添加的是一个元组
3、最外层是用AND连接
Django中的ORM进阶操作的更多相关文章
- Django中的ORM相关操作:F查询,Q查询,事物,ORM执行原生SQL
一 F查询与Q查询: 1 . F查询: 在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较.如果我们要对两个字段的值做比较,那该怎么做呢? Django 提供 F() 来做这样的 ...
- 在django中使用orm来操作MySQL数据库的建表,增删改
多张表之间的三种关系:一对一,一对多,多对多 创建表 一对一 xx = models.OneToOneField(to='表明',to_field='字段名',on_delete=models.CAS ...
- 在Django中使用ORM创建图书管理系统
一.ORM(对象关系映射) 很多语言的web框架中都有这个概念 1. 为什么要有ORM? 1. 写程序离不开数据,要使用数据就需要连接数据库,但是不同的数据库在sql语句上(mysql,oracle等 ...
- Django中的ORM框架使用小技巧
Django中的ORM框架使用小技巧 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Django对各个数据提供了很好的支持,包括PostgreSQL,MySQL,SQLite ...
- django中的ORM介绍和字段及字段参数
Object Relational Mapping(ORM) ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据 ...
- Django中的ORM介绍,字段以及字段的参数。
Object Relational Mapping(ORM) ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据 ...
- Django框架 之 ORM查询操作详解
Django框架 之 ORM查询操作详解 浏览目录 一般操作 ForeignKey操作 ManyToManyField 聚合查询 分组查询 F查询和Q查询 事务 Django终端打印SQL语句 在Py ...
- Django 中得ORM介绍和字段及字段参数
ORM 介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术. 简单的说 ORM 是通过使用 ...
- django中的ORM与 应用与补充
目录 django中的ORM与 应用与补充 ORM与数据的对应关系 ORM 常用字段 ORM 其他字段 自定义字段 字段参数 Model Meta参数 常用13中查询(必会) 单表查询的双下划线应用 ...
随机推荐
- 再看JavaScript线程
继上篇讨论了一些关于JavaScript线程的知识,我们不妨回过头再看看,是不是JavaScript就不能多线程呢?看下面一段很简单的代码(演示用,没考虑兼容问题): 代码判断一: <div i ...
- 让你的 Node.js 应用跑得更快的 10 个技巧
Node.js 受益于它的事件驱动和异步的特征,已经很快了.但是,在现代网络中只是快是不行的.如果你打算用 Node.js 开发你的下一个Web 应用的话,那么你就应该无所不用其极,让你的应用更快,异 ...
- How to get Directory size in IsolatedStorage of Windows Phone 8 App
There is no API to get the total size of a specific directory in the isolated storage. Therefore, th ...
- “父窗口拖动的时候Popup不随着父窗口移动”问题的解决方案
我们用WPF用的Popup时候会发现,当 StaysOpen=True 的时候,因为Popup不会消失,在父窗口移走的时候Popup仍旧在原地...作者在国外网站上无意间发现了这个解决方案,拿出来给大 ...
- 2016030207 - sql50题练习(脚本)
我的mysql版本是5.下面是要进行sql练习题使用的脚本.脚本是我整理出来的,在我本地直接复制执行就可以使用! 参考网址是:http://blog.csdn.net/zhangyulin54321/ ...
- PDF转WORD工具 Solid Converter PDF v9.1.6744
Solid Converter PDF中文破解版(pdf转换成word转换器)是一款功能强大的PDF格式转换软件.Solid Converter PDF允许用户将PDF转换为Word(PDF to W ...
- 什么是xsi:type ???
http://www.w3.org/2001/XMLSchema-instance http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.ecli ...
- find+*的问题
转自find+*的问题 不久前做移植的时候想把某个目录下的C文件都找出来,然后拷贝下,结果一直报错,我用的是*.c作为pattern.今天看论坛的时候知道为什么了. $ ls test2.c tes ...
- Cloud Insight 客户案例-晨芯时代科技有限公司
在不断迭代的过程中,Cloud Insight 也很重视客户对产品的使用体验,这次我们拜访了晨芯时代,了解到他们在使用 Cloud Insight 过程中对产品的一些想法. 客户背景 晨芯时代是一家开 ...
- Android 网络请求详解
我们知道大多数的 Android 应用程序都是通过和服务器进行交互来获取数据的.如果使用 HTTP 协议来发送和接收网络数据,就免不了使用 HttpURLConnection 和 HttpClient ...