首先推荐两篇文章:Django之ORM操作http://www.cnblogs.com/yuanchenqi/articles/6083427.html十分全面。

另外和python---ORM之SQLAlchemy(1)等前面几篇文章相结合

1.ORM对象关系映射(Object Relational Mapping)

优点:

使用orm,对于数据库迁移十分有用,只需要修改相关引擎即可,
不用考虑是sqlite还是mysql,oracle等,
而且设计好类后,会自动生成相关表,数据。
但是对于一些简单的表可能会稍微有点多余,但是毕竟优点多余这些

orm类大概了解:

类名对应      数据库表名
类成员属性对应  数据库字段
类实例对应    数据库表中的一行数据

注意:使用orm时对应的数据库是在settings文件中红设置的,必须提前建库

create database 库名 default character set utf8 collate utf8_general_ci

相关配置请看python---django中models配置

2.模型常用字段类型介绍

   models.CharField
#字符串字段,用于可变长字符串(varchar)
#要求必须有一个参数maxlength,用于设置其所允许的最大字符串长度 models.IntegerField
#用于保存一个整数 choice=(
(,'男'),
(,"女"),
(,"其他"),
)
models.IntegerField(choices=choice)
# 枚举类型 models.FloatField
#浮点数保存,必须提供两个参数,max_digits总位数,decimal_places小数位数 models.AutoField
#一个IntegerField,添加记录时,自动增长
#一般主键设置为他,models.AutoField(primary_key=True)
#若是不指定主键,系统会自动添加一个主键字段到该表 models.TextField
#一个容量很大的文本字段
models.DateField
#一个日期字段,可以带以下可选参数
#Argument 描述
#auto_now 当对象被保存时自动将该字段的值设为当前时间,通常表示“last-modified”时间戳,最后一次修改的时间
#auto_new_add 当对象被创建时设置,即首次添加时的创建时间 models.DateTimeField
#一个日期时间字段,和DateField类似 以下在数据库中本质都是字符串数据类型,此类字段只是在Django自带的admin中有用
    models.EmailField
#检测email合法性的CharField,不需要maxlength
  models.FileField 
  #一个文件上传字段
  
  
  models.ImageField
  #图片上传字段,类似FileField
  
  
  models.IPAddressField
  #ip检验字段
  .....

其他字段:

db_index = True 表示设置索引
unique(唯一的意思) = True 设置唯一索引 联合唯一索引
class Meta:
unique_together = (
('email','ctime'),
)
联合索引(不做限制)
index_together = (
('email','ctime'),
) ManyToManyField(RelatedField) #多对多操作

3.字段参数:

null                 :    为空
default : 设置默认值
primary_key : 主键 若是自己没有设置主键,Django会自动添加上id = meta.AutoField('ID', primary_key=True)
unique : 数据唯一
verbose_name : admin中字段的显示名称
db_column,
db_index : 如果为真,将为这个字段创建索引
choices : 一个用于选择的二维元组,枚举
.....

4.数据表的增删改查

表创建:

from django.db import models<br>
class Publisher(models.Model):
name = models.CharField(max_length=, verbose_name="名称")
address = models.CharField("地址", max_length=)
city = models.CharField('城市',max_length=)
state_province = models.CharField(max_length=)
country = models.CharField(max_length=)
website = models.URLField() class Meta:
verbose_name = '出版商'
verbose_name_plural = verbose_name def __str__(self):
return self.name class Author(models.Model):
name = models.CharField(max_length=)
def __str__(self):
return self.name class AuthorDetail(models.Model):
sex = models.BooleanField(max_length=, choices=((, '男'),(, '女'),))
email = models.EmailField()
address = models.CharField(max_length=)
birthday = models.DateField()
author = models.OneToOneField(Author) class Book(models.Model):
title = models.CharField(max_length=)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
price=models.DecimalField(max_digits=,decimal_places=,default=)
def __str__(self):
return self.title
from 应用APP.models import *

增(create, save):

方式一:

Author.objects.create(name='das')

方法二:

Author.objects.create(**{"name":"dsaf"})  推荐
方法三: author = Author(name="dsa") author.save() 方法四: author = Author() author.name="dsa"
author.save()

删delete:

Book.objects.filter(id=).delete() #先查找到这条数据,再删除

默认是级联删除,含有相关的这条记录的数据,也会被删除

对于外键中的级联删除,我们可以使用on_delete参数进行修改

改update,save:

author = Author.objects.get(id=)
author.name="gae"
author.save() Author.objects.filter(id=).update(name="geag") update效率高于save,save会重新保存所有字段,update只会修改你修改的相关字段

注意:第二种方式修改不能用get的原因是:update是QuerySet对象的方法,get返回的是一个model对象,它没有update方法,而filter返回的是一个QuerySe集合对象(filter里面的条件可能有多个条件符合,比如name='alvin',可能有两个name='alvin'的行数据),get返回的是一个记录对象。

查:

filter(**kwargs)
all()
get(**kwargs) 下面方法都是对查询的结果进行操作
values(*field) #返回字典序列
exclude(**kwargs) #它包含了与所给筛选条件不匹配的对象
order_by(*field)
reverse()
distinct()#剔除重复
values_list(*field) #元组序列
count()
first()
last()
exists()  #如果QuerySet包含数据,就返回True,否则返回False。判断对象是否存在数据,不会去取出数据(关于惰性机制)

更多方法查看:http://www.cnblogs.com/yuanchenqi/articles/6083427.html

queryset惰性机制了解:

惰性机制:当使用filter()或者all()等都是返回一个QuerySet()查询结果集对象,
他不会马上执行SQL语句,只有当调用QuerySet的时候才会被执行

可以查看SQL语句来进行分析:可以使用queryset.query()  { queryset是获取的queryset结果集 }获取该对象这一条数据的SQL语句

  queryset = MyModel.objects.all()
print 'query sql: ' + str(queryset .query)

也可以通过日志来查看,需要先配置settings文件

LOGGING = {
'version': ,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}

settings.py中SQL日志配置

class Handler(Filterer)   #基类

有下面两种方式:
class StreamHandler(Handler) #流输出 class FileHandler(StreamHandler) #文件形式

日志类型

然后可以开始测试:

from blog import models

def data_oper(req):
obj_set = models.Book.objects.filter(id=) #获取queryset结果集 return HttpResponse("<h1>ok</h1>")

执行后发现,并没有SQL日志产生,所有SQL语句没有执行,只有当使用queryset集合是才会开始执行。

def data_oper(req):
obj_set = models.Book.objects.filter(id=) #获取queryset结果集 for obj in obj_set :
print(obj.title)
return HttpResponse("<h1>ok</h1>")

此时会发现执行了查询数据的SQL语句。

缺点分析:

def data_oper(req):
obj_set = models.Book.objects.filter(id=)
if obj_set:    #if 逻辑判断只需要知道其中是否包含数据,需要快速执行,但是在这里会去执行SQL语句,将逻辑语句效率降低
print("ok")
return HttpResponse("<h1>ok</h1>")
#高效判断,可以使用exists方法 #取数据时,也可以不用一次性取完,可以使用迭代器,一条一条数据取出
obj_set.iterator()

缓存:

def data_oper(req):
obj_set = models.Book.objects.filter(id=) #获取queryset结果集 for obj in obj_set : #去数据库中取数据,第一次执行后会将queryset数据存放在缓存中,后面获取数据时,则不需要在进行SQL语句
print(obj.title)
  
   #若是在这里修改
   #obj_set.update(title="dsaf") #会修改数据库数据,也会修改缓存数据
for obj in obj_set : #不需要在进行SQL语句,缓存中取数据
print(obj.title)
return HttpResponse("<h1>ok</h1>")

补充:QuerySet

QuerySet特点:可迭代,可切片

objs=models.Book.objects.all()#[obj1,obj2,ob3...]

    #QuerySet:   可迭代

    for obj in objs:#每一obj就是一个行对象  或者:obj_set.iterator()获取数据,可用while
    print("obj:",obj)
    # QuerySet:  可切片

    # print(objs[])
# print(objs[:])
# print(objs[::-])

高效使用:

<>Django的queryset是惰性的

     Django的queryset对应于数据库的若干记录(row),通过可选的查询来过滤。例如,下面的代码会得
到数据库中名字为‘Dave’的所有的人:person_set = Person.objects.filter(first_name="Dave")
上面的代码并没有运行任何的数据库查询。你可以使用person_set,给它加上一些过滤条件,或者将它传给某个函数,
这些操作都不会发送给数据库。这是对的,因为数据库查询是显著影响web应用性能的因素之一。 <>要真正从数据库获得数据,你可以遍历queryset或者使用if queryset,总之你用到数据时就会执行sql.
为了验证这些,需要在settings里加入 LOGGING(验证方式)
obj=models.Book.objects.filter(id=)
# for i in obj:
# print(i) # if obj:
# print("ok") <>queryset是具有cache的
当你遍历queryset时,所有匹配的记录会从数据库获取,然后转换成Django的model。这被称为执行
(evaluation).这些model会保存在queryset内置的cache中,这样如果你再次遍历这个queryset,
你不需要重复运行通用的查询。
obj=models.Book.objects.filter(id=) # for i in obj:
# print(i)
## models.Book.objects.filter(id=).update(title="GO")
## obj_new=models.Book.objects.filter(id=)
# for i in obj:
# print(i) #LOGGING只会打印一次 <>
简单的使用if语句进行判断也会完全执行整个queryset并且把数据放入cache,虽然你并不需要这些
数据!为了避免这个,可以用exists()方法来检查是否有数据: obj = Book.objects.filter(id=)
# exists()的检查可以避免数据放入queryset的cache。
if obj.exists():
print("hello world!") <>当queryset非常巨大时,cache会成为问题 处理成千上万的记录时,将它们一次装入内存是很浪费的。更糟糕的是,巨大的queryset可能会锁住系统
进程,让你的程序濒临崩溃。要避免在遍历数据的同时产生queryset cache,可以使用iterator()方法
来获取数据,处理完数据就将其丢弃。
objs = Book.objects.all().iterator()
# iterator()可以一次只从数据库获取少量数据,这样可以节省内存
for obj in objs:
print(obj.name)
#BUT,再次遍历没有打印,因为迭代器已经在上一次遍历(next)到最后一次了,没得遍历了
for obj in objs:
print(obj.name) #当然,使用iterator()方法来防止生成cache,意味着遍历同一个queryset时会重复执行查询。所以使
#用iterator()的时候要当心,确保你的代码在操作一个大的queryset时没有重复执行查询 总结:
queryset的cache是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。
使用exists()和iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能
会造成额外的数据库查询。

5.一对多,多对多

一对多,外键foreign_key

class Book(models.Model):
title = models.CharField(max_length=)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
price=models.DecimalField(max_digits=,decimal_places=,default=)
def __str__(self):
return self.title

Book

class Publisher(models.Model):
name = models.CharField(max_length=, verbose_name="名称")
address = models.CharField("地址", max_length=)
city = models.CharField('城市',max_length=)
state_province = models.CharField(max_length=)
country = models.CharField(max_length=)
website = models.URLField() class Meta:
verbose_name = '出版商'
verbose_name_plural = verbose_name def __str__(self):
return self.name

Publisher

增加:

一对多:

方法一:直接添加外键值

Book.objects.create(title='php',
publisher_id=, #这里的2是指为该book对象绑定了Publisher表中id=2的行对象
publication_date='2017-7-7',
price=)
注意: publisher = models.ForeignKey(Publisher)
外键就是在foreign基础上,加上一个_id
例如:publisher外键,在数据库存在为publisher_id,所以调用时也应该使用publisher_id
方法二:直接添加对象,则不需要管外键_id了 对象创建或查找: pub_obj=Publisher(name='河大出版社',address='保定',city='保定',state_province='河北',country='China',website='http://www.hbu.com')
#直接新建
或者
pub_obj=Publisher.objects.get(id=)
#查找
添加加入:将 publisher_id= 改为 publisher=pub_obj Book.objects.create(title='php',
publisher=pub_obj,
publication_date='2017-7-7',
price=)

补充:连续跨多张表:

class School(models.Model):
title = models.CharField(max_length=32) class Classes(models.Model):
sc = models.ForeignKey(School)
caption = models.CharField(max_length=32)
def __str__(self):
return self.caption class Student(models.Model):
username = models.CharField(max_length=32)
age = models.IntegerField()
gender = models.BooleanField()
cls = models.ForeignKey("Classes") #跨多表查询
#跨一表查询班级信息
stu_list = Student.objects.all().values('username',"cls__caption")
#跨两张表查询学校
stu_list = Student.objects.all().values('username',"cls__caption","cls__sc__title")

补充:related_name:相当于在Classes表中加入了一个ccc字段,是指向Student表,反向查询(有这个就可以直接使用这个字段进行反向查询,不需要字段_set来进行操作)

class Student(models.Model):
username = models.CharField(max_length=32)
age = models.IntegerField()
gender = models.BooleanField()
cls = models.ForeignKey("Classes",related_name="ccc") obj = Classes.objects.filter(caption="python").first()
Stu_set = obj.ccc.all() #关于python班级下的所有学生的query_set集合

就是tornado中的relationship中的backref参数python---ORM之SQLAlchemy(3)外键与relationship的关系

注:尽量使用正向查询

补充:一对多---->一对一  对应关系

只需要在外键中设置为unique=true

一对一:反向查找只需要在后面加上反向的表名即可

一对多:反向查找需要在后面跟上反向的小写表名+_set

多对多:像书籍和作者

class Book(models.Model):
title = models.CharField(max_length=)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
price=models.DecimalField(max_digits=,decimal_places=,default=) def __str__(self):
return self.title
class Author(models.Model):
name = models.CharField(max_length=)
def __str__(self):
return self.name

这个多对多键也可以设在Author中,最好应该是在数据较多的一侧,去查找少的

多对多一般会创建第三张表来保存数据,第三张表是通过models.ManyToManyField()自动创建,默认是  应用APP_表一名_表二名,会自动生成主键,将两张表的主键作为记录,字段名为:表名_id,并且是联合唯一。

但是:

对于Django自动创建的这张表,我们无法自己直接使用,使用方法如下:add   remove

     因为author字段放在book表中,所以下面是正向查询 
   author1=Author.objects.get(id=)
author2=Author.objects.filter(name='alvin')[]
book=Book.objects.get(id=)
book.authors.add(author1,author2)   #上面可以写为
book.authors.add(*[author1,author2])    对应删除操作:
   book.authors.remove(*[author1,author2])

或者:

    author表中并没有book字段,所以为反向查询  ---》  反向查询直接找author中book对象是找不到的,
需要使用_set才可以找到
   book=models.Book.objects.filter(id__gt=)
authors=models.Author.objects.filter(id=)[]
authors.book_set.add(*book) 对应删除操作:
   authors.book_set.remove(*book)

或者:

book.authors.add()
authors.book_set.add() 对应删除操作:
book.authors.remove(1)
authors.book_set.remove(1)

查询方法:

# Create your models here.
class Classes(models.Model):
caption = models.CharField(max_length=) class Teacher(models.Model):
name = models.CharField(max_length=)
cls = models.ManyToManyField('Classes',related_name="ssss") Teacher.objects.all().values('id','name','cls','cls__caption')
#默认直接访问cls是获取其id,使用__连表获取信息
Classes.objects.all().values('id','caption','ssss','ssss_name')

要想直接使用第三张表进行操作,需要我们自己创建该表(使用方便)

当不使用ManyToManyField自动创建表时,自己手动创建第三张表:


from django.db import models
class Book2Author(models.Model)
book=models.ForeignKey("Book")
author=models.ForeignKey("Author")  #最好使用引号,若是想不加引号,那么必须将那个类放在前面
  
   #联合唯一
   class Meta:  #在元类中添加联合唯一,建联合唯一要根据需求来看
     unique_together = ['book','author']

此时可以直接使用第三张表去添加数据:

from 应用APP import models

models.Book2Author.objects.create(
book_id=,
author_id=
)

注:上面两类models是不一样的

补充:正向操作也可以操作关联表(咂filter字段操作时)

class Role(models.Model):
caption = models.CharField(max_length=)
class Meta:
verbose_name_plural = "角色表"
def __str__(self):
return self.caption class User2Role(models.Model):
u = models.ForeignKey("User")
r = models.ForeignKey("Role") class Meta:
verbose_name_plural = "用户角色分配表"
def __str__(self):
return "%s:%s"%(self.u.username,self.r.caption)
class Permission2Action2Role(models.Model):
p2a = models.ForeignKey("Permission2Action")
r = models.ForeignKey("Role") class Meta:
verbose_name_plural = "角色权限分配表"
def __str__(self):
return "%s:%s"%(self.r.caption,self.p2a)

使用时:

    role_list = models.Role.objects.filter(user2role__u__id=id).all()

    user = models.User.objects.filter(id=int(id)).get()
role_list2 = models.Role.objects.filter(user2role__u = user)

测试可用字段:

role_list2 = models.Role.objects.filter(aaa = user)    #aaa不存在,错误提示中会显示我们所能调用的字段

django.core.exceptions.FieldError: Cannot resolve keyword 'aaa' into field.
Choices are: caption, id, permission2action2role, user2role

filter使用时可以正向操作字段,对象使用时需要加上_set

python---django中orm的使用(1)的更多相关文章

  1. Django中ORM介绍和字段及其参数

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

  2. Django中ORM介绍和字段及字段参数 Object Relational Mapping(ORM)

    Django中ORM介绍和字段及字段参数   Object Relational Mapping(ORM) ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简 ...

  3. Django 中ORM 的使用

    一:Django 中 orm 的使用 1:手动新建一个数据库 2 :告诉Django连接哪个数据库 settings.py里配置数据库连接信息: #数据库相关的配置项 DATABASES ={ 'de ...

  4. 关于Django中ORM数据库迁移的配置

    Django中ORM数据库迁移配置 1,若想将模型转为mysql数据库中的表,需要在settings中配置: DATABASES = { 'default': { 'ENGINE': 'django. ...

  5. Django中ORM的使用

    Django中ORM的使用 ORM orm(object-relation-mapping)对象关系映射,即用对象来表示关系数据库中的表: 类 --> 表, 对象-->一行数据 对象的属性 ...

  6. Django中ORM对数据库的增删改查

    Django中ORM对数据库数据的增删改查 模板语言 {% for line in press %} {% line.name %} {% endfor %} {% if 条件 %}{% else % ...

  7. 6月20日 Django中ORM介绍和字段、字段参数、相关操作

    一.Django中ORM介绍和字段及字段参数 二.Django ORM 常用字段和参数 三.Django ORM执行原生SQL.在Python脚本中调用Django环境.Django终端打印SQL语句 ...

  8. Django中ORM实际应用

    1. Django中ORM的使用 1. 手动新建一个数据库 2. 告诉Django连接哪个数据库 settings.py里面配置数据库连接信息: # 数据库相关的配置项 DATABASES = { ' ...

  9. Python Django中QQ邮箱授权码问题

    Python Django中QQ邮箱授权码问题 系统及软件版本如下: Ubuntu Kylin 16.04 Python 3.5.1 Django 1.9.7 PyCharm Community Ed ...

  10. Django中ORM的聚合索引

    Django中ORM的聚合索引   在Django中,聚合函数是通过aggregate方法实现的,aggregate方法返回的结果是一个字典 在使用时需要先导入模块from django.db.mod ...

随机推荐

  1. Java虚拟机笔记(五):JVM中对象的分代

    为什么要分代 为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我们要找到哪些对象没用, ...

  2. binlog2sql使用总结

    binlog2sql是大众点评开源的一款用于解析binlog的工具,在测试环境试用了下,还不错. 其具有以下功能 1. 提取SQL 2. 生成回滚SQL 关于该工具的使用方法可参考github操作文档 ...

  3. 基于.NET的3D开发框架/工具比较

    好久木有写博客了,这么日子以来忙忙碌碌的,也没大有时间潜心学习和梳理.最近刚好接手一个3D显示的活,虽然还没怎么弄明白,但是也看过一些方案,走了一些弯路,经过一些浅显的了解(3D Display这里面 ...

  4. 用信鸽来讲解HTTPS的知识

    加密是一个很难理解的东西,这里头满是数学证明.不过,除非你是在开发一个加密系统,否则无需了解那些高阶的复杂知识. 如果你看这篇文章是为了创造下一个 HTTPS 协议,很抱歉,请出门左走,鸽子是远远不够 ...

  5. 在windows10上安装caffe和tensorflow

    最近在Windows10上安装了caffe和tensorflow,折腾了好久.在此记录一下. 安装caffe的过程已在另一篇博客中进行了记录,在此不再赘述.而tensorflow也是非常简单的,也不再 ...

  6. nodejs mongodb 查询要看的文章

    http://www.cnblogs.com/refactor/archive/2012/07/30/2591344.html 数组很大多数情况下可以这样理解:每一个元素都是整个键的值. db.use ...

  7. 词频统计 SPEC 20160911

    本文档随时可能修改,并且没有另行通知. 请确保每一次在开始修改你的代码前,读标题中的日期,如果晚于你上次阅读, 请重读一次. 老五在寝室吹牛他熟读过<鲁滨逊漂流记>,在女生面前吹牛热爱&l ...

  8. 课堂讨论——Alpha版总结会议

    我们在课堂上针对第一阶段冲刺过程中存在的问题,展开了激烈的讨论,并投票选出需要改进的最主要三个问题.

  9. 2018软工实践—Beta冲刺(7)

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Beta 冲鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调组内工作 整体软件测试 展示GitHub当日代码/文档签入记录(组 ...

  10. Smart Disk -- proposed by Liyuan Liu

    Need 如今,照相渐渐得成为了人们的日常举动.几乎所有的人都在随时随地得照相.手机,相机,平板越来越多的设备对照相进行了支持,同时, 照片以一种前所未有的速度渐渐淹没我们的文件夹.而寻找照片,对照片 ...