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进阶操作的更多相关文章

  1. Django中的ORM相关操作:F查询,Q查询,事物,ORM执行原生SQL

    一    F查询与Q查询: 1 . F查询: 在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较.如果我们要对两个字段的值做比较,那该怎么做呢? Django 提供 F() 来做这样的 ...

  2. 在django中使用orm来操作MySQL数据库的建表,增删改

    多张表之间的三种关系:一对一,一对多,多对多 创建表 一对一 xx = models.OneToOneField(to='表明',to_field='字段名',on_delete=models.CAS ...

  3. 在Django中使用ORM创建图书管理系统

    一.ORM(对象关系映射) 很多语言的web框架中都有这个概念 1. 为什么要有ORM? 1. 写程序离不开数据,要使用数据就需要连接数据库,但是不同的数据库在sql语句上(mysql,oracle等 ...

  4. Django中的ORM框架使用小技巧

      Django中的ORM框架使用小技巧 作者:尹正杰  版权声明:原创作品,谢绝转载!否则将追究法律责任. Django对各个数据提供了很好的支持,包括PostgreSQL,MySQL,SQLite ...

  5. django中的ORM介绍和字段及字段参数

    Object Relational Mapping(ORM) ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据 ...

  6. Django中的ORM介绍,字段以及字段的参数。

    Object Relational Mapping(ORM) ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据 ...

  7. Django框架 之 ORM查询操作详解

    Django框架 之 ORM查询操作详解 浏览目录 一般操作 ForeignKey操作 ManyToManyField 聚合查询 分组查询 F查询和Q查询 事务 Django终端打印SQL语句 在Py ...

  8. Django 中得ORM介绍和字段及字段参数

    ORM 介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术. 简单的说 ORM 是通过使用 ...

  9. django中的ORM与 应用与补充

    目录 django中的ORM与 应用与补充 ORM与数据的对应关系 ORM 常用字段 ORM 其他字段 自定义字段 字段参数 Model Meta参数 常用13中查询(必会) 单表查询的双下划线应用 ...

随机推荐

  1. sass中常用mixin

    //设置字体大小 @mixin font($s:14px,$h:1.5,$f:microsoft yahei){ font:$s/#{$h} $f; } //参数(方向,大小,颜色),默认:向下,10 ...

  2. JavaScript符串中每个单词的首字母大写化

    map() + replace() function titleCase(str) { var convertToArray = str.toLowerCase().split(" &quo ...

  3. ASP.net+MVC--2

    1.ASP.NET MVC控制器 1)在Controllers文件夹下新建控制类 public class HelloWorld2Controller : Controller { public st ...

  4. xml之phpdom操作

    php xml编程XML解析技术介绍 1.php与DOM 2.PHP与XPath 3.SimpleXML DOM(document object model)文档对象模型 把一个文件看做一个对象模型, ...

  5. Delphi接口

    program Demo1; { Create Date: 2014-06-29 Author: P.S.M 1.接口Demo1 } {$APPTYPE CONSOLE} uses SysUtils; ...

  6. jquery mobile页面跳转后,必须重新刷新页面js方可有效

    最近在做个项目,用到jquery mobile,很陌生对他,问题一个个的来,那就要一个个解决,找了一天这个问题,放可明白:首先明白jqm里面页面跳转默认都是通过ajax请求的,必须重新刷新页面js方可 ...

  7. 用JS实现避免重复加载相同js文件

    我们在日常开发过程中,可能有重复加载同一个资源例如:1.js,为了提高性能和用户体验这里我们用原生JS实现同一个资源只加载一次. 下面是 common.js里的JS代码 //使用沙箱模式防止污染外面的 ...

  8. UISearchBar -- 备忘

    搜索功能的备忘 UISearchBar UISearchBar是一个搜索栏,继承自UIView,也是常用的控件之一,所以特别写一篇备忘方便以后做工具文章. 例子: let searchBar = UI ...

  9. FFMPEG视音频编解码零基础学习方法-b

    感谢大神分享,虽然现在还看不懂,留着大家一起看啦 PS:有不少人不清楚“FFmpeg”应该怎么读.它读作“ef ef em peg” 0. 背景知识 本章主要介绍一下FFMPEG都用在了哪里(在这里仅 ...

  10. JS身份证真实性校验(一)

    //这个可以验证15位和18位的身份证,并且包含生日和校验位的验证. //如果有兴趣,还可以加上身份证所在地的验证,就是前6位有些数字合法有些数字不合法. function isIdCardNo(nu ...