什么是ORM

  ORM,即Object-Relational Mapping(对象关系映射),它的作用是在关系型数据库和业务实体对象之间作一个映射,这样,我们在具体的操作业务对象的时候,就不需要再去和复杂的SQL语句打交道,只需简单的操作对象的属性和方法。

ORM的优缺点是什么

优点:摆脱复杂的SQL操作,适应快速开发;让数据结构变得简洁;数据库迁移成本更低(如从mysql->oracle)

缺点:性能较差、不适用于大型应用;复杂的SQL操作还需通过SQL语句实现。

ORM跟数据库的对应关系

     表名  <-------> 类名

       字段  <-------> 属性

    表记录 <------->类实例对象

既然是在操作数据库,那么无非就是创建表,对表中记录的增删改查。我们学习的就是用django中的ORM怎么去操作数据库。

创建表

from django.db import models

class Book(models.Model):
name=models.CharField(max_length=32)
price=models.DecimalField(max_digits=5,decimal_places=2)
publish_date=models.DateField()
# 与Publish建立一对多的关系,外键字段建立在多的一方
publish=models.ForeignKey("Publish")
# 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
author=models.ManyToManyField("Author") class Author(models.Model):
name=models.CharField(max_length=32)
age=models.IntegerField()
phone=models.IntegerField()
addr=models.EmailField() class Publish(models.Model):
name=models.CharField(max_length=32)
addr=models.CharField(max_length=32)
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}  

在配置文件中加它就可以查看翻译成的sql语句

运行命令
python manage.py makemigrations python manage.py migrate

注意事项:

1、 表的名称myapp_modelName,是根据 模型中的元数据自动生成的,也可以覆写为别的名称  

2、id 字段是自动添加的

3、对于外键字段,Django 会在字段名上添加"_id" 来创建数据库中的列名

4、这个例子中的CREATE TABLE SQL 语句使用PostgreSQL 语法格式,要注意的是Django 会根据settings 中指定的数据库类型来使用相应的SQL 语句。

5、定义好模型之后,你需要告诉Django _使用_这些模型。你要做的就是修改配置文件中的INSTALL_APPSZ中设置,在其中添加models.py所在应用的名称。

6、外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 。

表记录的操作

添加:

普通字段:直接类实例化对象然后用.save保存或者用.create()返回值是添加记录的对象。

外键字段:先找到外键关联的那个字段对象,然后直接赋值给他的属性。

多对多字段:用.add方法 添加   .remove()移除 .clear() 清除所有

查询:

查询相关API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<1all():                 查询所有结果
 
<2filter(**kwargs):      它包含了与所给筛选条件相匹配的对象
 
<3> get(**kwargs):         返回与所给筛选条件相匹配的对象,返回结果有且只有一个,
                           如果符合筛选条件的对象超过一个或者没有都会抛出错误。
 
<5> exclude(**kwargs):     它包含了与所给筛选条件不匹配的对象
 
<4> values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
                           model的实例化对象,而是一个可迭代的字典序列
 
<9> values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
 
<6> order_by(*field):      对查询结果排序
 
<7> reverse():             对查询结果反向排序
 
<8> distinct():            从返回结果中剔除重复纪录
 
<10> count():              返回数据库中匹配查询(QuerySet)的对象数量。
 
<11> first():              返回第一条记录
 
<12> last():               返回最后一条记录
 
<13> exists():             如果QuerySet包含数据,就返回True,否则返回False

注意:一定区分object与querySet的区别 !!!

双下划线之单表查询

1
2
3
4
5
6
7
8
9
10
11
models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值
 
models.Tb1.objects.filter(id__in=[112233])   # 获取id等于11、22、33的数据
models.Tb1.objects.exclude(id__in=[112233])  # not in
 
models.Tb1.objects.filter(name__contains="ven")
models.Tb1.objects.filter(name__icontains="ven"# icontains大小写不敏感
 
models.Tb1.objects.filter(id__range=[12])      # 范围bettwen and
 
startswith,istartswith, endswith, iendswith 

基于对象的跨表查询

一对多查询(Publish 与 Book)

正向查询(按字段:publish):

1
2
# 查询nid=1的书籍的出版社所在的城市<br>
book_obj=Book.objects.get(nid=1)<br>print(book_obj.publish.city) # book_obj.publish 是nid=1的书籍对象关联的出版社对象  

反向查询(按表名:book_set):

1
2
3
4
5
6
7
8
# 查询 人民出版社出版过的所有书籍
 
    publish=Publish.objects.get(name="人民出版社")
 
    book_list=publish.book_set.all()  # 与人民出版社关联的所有书籍对象集合
 
    for book_obj in book_list:
        print(book_obj.title)

多对多查询 (Author 与 Book)

正向查询(按字段:authors):

1
2
3
4
5
6
7
8
9
# 呐喊所有作者的名字以及手机号
 
    book_obj=Book.objects.filter(title="呐喊").first()
 
    authors=book_obj.authors.all()
 
    for author_obj in authors:
 
        print(author_obj.name,author_obj.authorDetail.telephone)

反向查询(按表名:book_set):

1
2
3
4
5
6
7
# 查询鲁迅出过的所有书籍的名字
 
    author_obj=Author.objects.get(name="鲁迅")
    book_list=author_obj.book_set.all() #与鲁迅作者相关的所有书籍
 
    for book_obj in book_list:
        print(book_obj.title)

注意:

你可以通过在 ForeignKey() 和ManyToManyField的定义中设置 related_name 的值来覆写 FOO_set 的名称。例如,如果 Article model 中做一下更改: publish = ForeignKey(Blog, related_name='bookList'),那么接下来就会如我们看到这般:

1
2
3
4
5
# 查询 人民出版社出版过的所有书籍
 
   publish=Publish.objects.get(name="人民出版社")
 
   book_list=publish.bookList.all()  # 与人民出版社关联的所有书籍对象集合

基于双下划线的跨表查询

Django 还提供了一种直观而高效的方式在查询(lookups)中表示关联关系,它能自动确认 SQL JOIN 联系。要做跨关系查询,就使用两个下划线来链接模型(model)间关联字段的名称,直到最终链接到你想要的 model 为止。

练习1:  查询人民出版社出版过的所有书籍的名字与价格(一对多)

    # 正向查询 按字段:publish

    queryResult=Book.objects
            .filter(publish__name="人民出版社")
            .values_list("title","price") # 反向查询 按表名:book queryResult=Publish.objects
              .filter(name="人民出版社")
              .values_list("book__title","book__price") # 练习2: 查询鲁迅出过的所有书籍的名字(多对多) # 正向查询 按字段:authors:
queryResult=Book.objects
            .filter(authors__name="鲁迅")
            .values_list("title") # 反向查询 按表名:book
queryResult=Author.objects
              .filter(name="鲁迅")
              .values_list("book__title","book__price") # 练习3: 查询人民出版社出版过的所有书籍的名字以及作者的姓名 # 正向查询
queryResult=Book.objects
            .filter(publish__name="人民出版社")
            .values_list("title","authors__name")
# 反向查询
queryResult=Publish.objects
              .filter(name="人民出版社")
              .values_list("book__title","book__authors__age","book__authors__name") # 练习4: 手机号以151开头的作者出版过的所有书籍名称以及出版社名称 queryResult=Book.objects
            .filter(authors__authorDetail__telephone__regex="")
            .values_list("title","publish__name")

聚合查询与分组查询

用聚合函数之前先导入它:from django.db.models import Avg,Count,Sum,Max,Min

聚合:aggregate(*args, **kwargs)

1
2
3
4
# 计算所有图书的平均价格
    >>> from django.db.models import Avg
    >>> Book.objects.all().aggregate(Avg('price'))
    {'price__avg'34.35}

aggregate()QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定一个名称,可以向聚合子句提供它。

1
2
>>> Book.objects.aggregate(average_price=Avg('price'))
{'average_price'34.35}

如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:

1
2
3
>>> from django.db.models import Avg, MaxMin
>>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
{'price__avg'34.35'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}

分组:annotate() 

(1) 练习:统计每一本书的作者个数

1
2
3
bookList=Book.objects.annotate(authorsNum=Count('authors'))
for book_obj in bookList:
    print(book_obj.title,book_obj.authorsNum)

练习:统计每一个出版社的最便宜的书

1
2
3
4
publishList=Publish.objects.annotate(MinPrice=Min("book__price"))
 
for publish_obj in publishList:
    print(publish_obj.name,publish_obj.MinPrice)

annotate的返回值是querySet,如果不想遍历对象,可以用上valuelist:

queryResult= Publish.objects
            .annotate(MinPrice=Min("book__price"))
            .values_list("name","MinPrice")
print(queryResult)

方式2: 

1
queryResult=Book.objects.values("publish__name").annotate(MinPrice=Min('price'))

注意:values内的字段即group by的字段

(3) 统计每一本以py开头的书籍的作者个数:

 queryResult=Book.objects
           .filter(title__startswith="Py")
           .annotate(num_authors=Count('authors'))

(4) 统计不止一个作者的图书:

queryResult=Book.objects
          .annotate(num_authors=Count('authors'))
          .filter(num_authors__gt=1)

(5) 根据一本图书作者数量的多少对查询集 QuerySet进行排序:

1
Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors')

(6) 查询各个作者出的书的总价格:

# 按author表的所有字段 group by
queryResult=Author.objects
              .annotate(SumPrice=Sum("book__price"))
              .values_list("name","SumPrice")
print(queryResult) #按authors__name group by
queryResult2=Book.objects.values("authors__name")
              .annotate(SumPrice=Sum("price"))
              .values_list("authors__name","SumPrice")
print(queryResult2)

F查询与Q查询

F查询

在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?

Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。

1
2
3
4
# 查询评论数大于收藏数的书籍
 
   from django.db.models import F
   Book.objects.filter(commnetNum__lt=F('keepNum'))

Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。

1
2
# 查询评论数大于收藏数2倍的书籍
    Book.objects.filter(commnetNum__lt=F('keepNum')*2)

修改操作也可以使用F函数,比如将每一本书的价格提高30元:

1
Book.objects.all().update(price=F("price")+30) 

Q查询

filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q 对象

1
2
from django.db.models import Q
Q(title__startswith='Py')

Q 对象可以使用& 和| 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。

1
bookList=Book.objects.filter(Q(authors__name="鲁迅")|Q(authors__name="冰心"))

等同于下面的SQL WHERE 子句:

1
WHERE name ="鲁迅" OR name ="冰心"

你可以组合& 和|  操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询:

1
bookList=Book.objects.filter(Q(authors__name="鲁迅") & ~Q(publishDate__year=2017)).values_list("title")

查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。例如:

    bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017),
title__icontains="python"
)

修改记录

方式一:

直接获取要修改的对象,然后对象 .属性 直接重新赋值,最后对象 . save 保存一下就可以了;

方式二:

获取要修改对象的query set ,用filter然后 .update()。(注意update是QuerySet对象的方法)

删除记录

删除方法就是 delete()。它运行时立即删除对象而不返回任何值。

你也可以一次性删除多个对象。每个 QuerySet 都有一个 delete() 方法,它一次性删除 QuerySet 中所有的对象。

在 Django 删除对象时,会模仿 SQL 约束 ON DELETE CASCADE 的行为,换句话说,删除一个对象时也会删除与它相关联的外键对象。

要注意的是: delete() 方法是 QuerySet 上的方法,但并不适用于 Manager 本身。这是一种保护机制,是为了避免意外地调用 Entry.objects.delete() 方法导致 所有的 记录被误删除。如果你确认要删除所有的对象,那么你必须显式地调用:

1
Entry.objects.all().delete()

 

Django框架中的model(操作数据库)的更多相关文章

  1. Python中的Django框架中prefetch_related()函数对数据库查询的优化

    实例的背景说明 假定一个个人信息系统,需要记录系统中各个人的故乡.居住地.以及到过的城市.数据库设计如下: Models.py 内容如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 1 ...

  2. 第三百零九节,Django框架,models.py模块,数据库操作——F和Q()运算符:|或者、&并且——queryset对象序列化

    第三百零九节,Django框架,models.py模块,数据库操作——F()和Q()运算符:|或者.&并且 F()可以将数据库里的数字类型的数据,转换为可以数字类型 首先要导入 from dj ...

  3. 第三百零八节,Django框架,models.py模块,数据库操作——链表结构,一对多、一对一、多对多

    第三百零八节,Django框架,models.py模块,数据库操作——链表结构,一对多.一对一.多对多 链表操作 链表,就是一张表的外键字段,连接另外一张表的主键字段 一对多 models.Forei ...

  4. 第三百零六节,Django框架,models.py模块,数据库操作——创建表、数据类型、索引、admin后台,补充Django目录说明以及全局配置文件配置

    Django框架,models.py模块,数据库操作——创建表.数据类型.索引.admin后台,补充Django目录说明以及全局配置文件配置 数据库配置 django默认支持sqlite,mysql, ...

  5. 四 Django框架,models.py模块,数据库操作——创建表、数据类型、索引、admin后台,补充Django目录说明以及全局配置文件配置

    Django框架,models.py模块,数据库操作——创建表.数据类型.索引.admin后台,补充Django目录说明以及全局配置文件配置 数据库配置 django默认支持sqlite,mysql, ...

  6. 第三百零七节,Django框架,models.py模块,数据库操作——表类容的增删改查

    Django框架,models.py模块,数据库操作——表类容的增删改查 增加数据 create()方法,增加数据 save()方法,写入数据 第一种方式 表类名称(字段=值) 需要save()方法, ...

  7. 五 Django框架,models.py模块,数据库操作——表类容的增删改查

    Django框架,models.py模块,数据库操作——表类容的增删改查 增加数据 create()方法,增加数据 save()方法,写入数据 第一种方式 表类名称(字段=值) 需要save()方法, ...

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

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

  9. Python的Django框架中forms表单类的使用方法详解

    用户表单是Web端的一项基本功能,大而全的Django框架中自然带有现成的基础form对象,本文就Python的Django框架中forms表单类的使用方法详解. Form表单的功能 自动生成HTML ...

随机推荐

  1. LeetCode 581. Shortest Unsorted Continuous Subarray (最短无序连续子数组)

    Given an integer array, you need to find one continuous subarray that if you only sort this subarray ...

  2. Dagger2 入门解析

    前言 在为dropwizard选择DI框架的时候考虑了很久.Guice比较成熟,Dagger2主要用于Android.虽然都是google维护的,但Dagger2远比guice更新的频率高.再一个是, ...

  3. django-rest-framework之序列化

    前言:昨天学习了rest-framework序列化方面的知识,故写了博客记录一下.官网:http://www.django-rest-framework.org/tutorial/1-serializ ...

  4. Java基础笔记7

    OOP面向对象有三个特点 1.封装 封装的好处: 起到一定的保护作用  封装的是属性. java如何进行封装; 1.使用private关键字对象属性封装. 只能在本类中使用.  2.为每个属性提供方法 ...

  5. iscroll 下拉刷新,上拉加载

    新手,直接贴代码了 <!DOCTYPE html><html class=""><head lang="en"><me ...

  6. Android中的intent属性

    android之Intent的七大属性 2015年04月03日 ⁄ Android ⁄ 共 14866字 ⁄ 字号 小 中 大 ⁄ 1条评论 Intent用于封装程序的“调用意图”.两个Activit ...

  7. Cable master

    Problem Description Inhabitants of the Wonderland have decided to hold a regional programming contes ...

  8. Page visibility 页面可见性

    一直以来,判断页面是不是当前可见标签,浏览器有没有缩小都是比较麻烦的.   通过页面可见性API可以获得相关信息document.hidden  判断页面当前是不是可见的document.visibi ...

  9. 单元测试 Qunit

    http://api.qunitjs.com/category/assert/    测试方法   选中 "Check for Globals" 会暴露全局对象,看你的代码会不会无 ...

  10. 通过扩大IE使用内存,解决skyline在IE下模型不能加载的方法

    环境:skyline TerraExploere 6.6.1,win10 专业版 64位,ie 11 情况描述:在ie下浏览三维场景,ie占用内存不断增大并且内存占用固定在一个最高范围内,三维场景中部 ...