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. 比较全面的gdb调试命令

    from:http://blog.csdn.net/xiajun07061225/article/details/8960332 http://blog.csdn.net/cjfeii/article ...

  2. [C#]异步委托使用小计

    APM(=Asynchronous Programming Model(=异步编程模型)) 使用 IAsyncResult 设计模式的异步操作是通过名为 Begin操作名称 和 End操作名称 的两个 ...

  3. 快速使用Log4Cpp

    封了一下接口,快速使用. 其他的你都不用管了. 这里封装了需要读取外部conf文件配置输出项.否则可以用getInstance初始化日志类 #include "L4Cpp.h" v ...

  4. 通过表名显示数据库中该表的表头和内容(mysql扩展库操作)

    编写一个函数,接收一个表名,然后把表的表头和内容显示在网页 <?php function readTab($tableName){ $conn=mysql_connect("local ...

  5. PHP图片上传程序(完整版)

    从PHP100上搜刮来的,功能很强大.几乎考虑到了每个细节,与大家分享!~~~ <meta http-equiv="Content-Type" content="t ...

  6. Makefile与shell脚本的区别

    引用博客:Makefile与shell脚本区别 在Makefile可以调用shell脚本,但是Makefile和shell脚本是不同的.本文试着归纳一下Makefile和shell脚本的不同. 1.s ...

  7. Uva 1354 Mobile Computing

    题目链接 题意: 在一个宽为r 的房间里, 有s个砝码, 每个天平的一端要么挂砝码, 要么挂另一个天平, 并且每个天平要保持平衡. 求使得所有砝码都放在天平上, 且总宽度不超过房间宽度的最大值. 思路 ...

  8. 关于Java(Hello World程序)

    详解 Hello World 应用程序 源码 class HelloWorldApp { public static void main(String[] args) { System.out.pri ...

  9. bzoj 3784: 树上的路径 堆维护第k大

    3784: 树上的路径 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 88  Solved: 27[Submit][Status][Discuss] ...

  10. Cloud Test 在手,宕机时让您不再措手不及

    1月28日,Github 上午 10:04 分宕机了,导致全球各地的用户不能访问.官方回复可能是网络中断引起的,到 10:28 分已经可以正常访问. 对于互联网公司来说,一旦宕机就会措手不及,如何才能 ...