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. PHP 面向对象之自定义类

    所谓面向对象就是什么时候什么东西做什么,我们设计类的时候需要想的就是怎么做的内容,那么怎么样的一个类才算是符合OOP的思想呢,答案是:这个类写好之后,在使用的过程中,能准确的代表一个事物,在书写的时候 ...

  2. epoll和select区别

    先说下本文框架,先是问题引出,然后概括两个机制的区别和联系,最后介绍每个接口的用法 一.问题引出 联系区别 问题的引出,当需要读两个以上的I/O的时候,如果使用阻塞式的I/O,那么可能长时间的阻塞在一 ...

  3. python 面向对象 class 老男孩选课系统

    要求:1. 创建北京.上海 2 所学校 class2. 创建linux , python , go 3个课程 , linux\py 在北京开, go 在上海开3. 课程包含,周期,价格,通过学校创建课 ...

  4. 【python】三个变量互换值

    >>> x = 1>>> y = 2>>> z = 3>>> y3>>> z1 大写的帅字! (来自小甲鱼习题 ...

  5. 4069: [Apio2015]巴厘岛的雕塑

    Description 印尼巴厘岛的公路上有许多的雕塑,我们来关注它的一条主干道. 在这条主干道上一共有 N 座雕塑,为方便起见,我们把这些雕塑从 1 到 N 连续地进行标号,其中第 i 座雕塑的年龄 ...

  6. maven的安装,maven库配置和Eclipse插件的安装

    maven的安装,maven库配置和Eclipse插件的安装 1.下载并解压maven 2.配置环境变量 3.配置maven配置文件 1.下载链接 Downloading Apache Maven 2 ...

  7. 记录一次配置unix网络编程环境的过程和遇到的问题

    记录一次搭建unix网络编程环境过程中遇到的问题和总结 计算机环境虚拟机 linuxmint-18-xfce-64bit 1.打开unix网络编程.iso 把目录下的文件复制到某一目录,修改权限,可命 ...

  8. jquery 判断是否 ie6 ie7 ie8

      var isIE = !!window.ActiveXObject; var isIE6 = isIE && !window.XMLHttpRequest; var isIE8 = ...

  9. 【技术贴】Maven打包文件增加时间后缀

    构建war包,或者jar包的,时候,maven会自动增加一个版本号和时间放在jar包后面比如poi-3.9-20131115.jar这样子,但是我自己打war包,总是给我生成一个快照的后缀report ...

  10. hdu 3062

    2-SAT的入门题: 网上说这个算法最好的入门教材是:伍昱的<由对称性解2-SAT问题>的ppt和赵爽的论文<2-SAT 解法浅析>: 看了一下伍昱的ppt,很好理解! 而这道 ...