Django ORM 使用手册

1. ORM简介

ORM:Object Relational Mapping(对象关系映射),通常把一个类和一张表一一对应,类的每个实例对应表的一条记录,类的每个属性对应表的每个字段。

ORM操作本质:根据对接的数据库引擎,翻译成对应的SQL语句;所有使用Django开发的项目无需关心底层使用的MySQL、Oracle、sqlite、PostgreSQL......,如果数据库迁移,只需要更换Django的数据库引擎即可。

ORM缺点:相比较直接使用SQL语句操作数据库,有性能损失;根据对象的操作转换成SQL语句,根据查询的结果转化成对象,在映射过程中有性能损失。

2. Django ORM

以Django项目使用PG数据库为例。

  1. 手动创建数据库
  2. 创建Django项目,在Django项目中的settings.py配置数据库连接信息

3)使用psycopg2连接PG数据库,一般是在与 settings.py 同级目录下的 __init__.py 中引入模块和进行配置

4)创建模型,

模型成员objects : 管理器对象

  • 是Manager类型的对象,定义在from django.db import models中
  • 用于模型对象和数据库交互
  • 是默认自动生成的属性,但是可以自定义管理器对象
  • 自定义管理器对象后,Django不再生成默认管理器对象objects

在项目中的models.py中添加如下类:

创建模型的参数介绍如下:

字段类型

描述

AutoField

自动增长的IntegerField, 不指定时Django会自动创建属性名为id的自动增长属性

BooleanField

布尔字段,值为True或False

NullBooleanField

支持Null、True、False三种值

CharField

字符串参数max_length表示最大字符个数

TextFiled

大文本字段,一般超过4000个字符时使用

IntegerField

整数

DecimalField

可以指定精度的十进制浮点数,max_digits表示总位数,decimal_places表示小数位数

FloatField

浮点数

DateField

日期,格式 YYYY-MM-DD,相当于Python中的datetime.date()实例

auto_now表示每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认false

auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认false

auto_now_add和auto_now是相互排斥的,组合将会发生错误

TimeField

参数和DateField一样

DateTimeField

日期,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例

FileField

上传文件字段,以二进制的形式

ImageField

继承于FileField,对上传的内容进行校验,确保是有效的图片

ForeignKey

外键,models.ForeignKey("Publish", on_delete=models.CASCADE)

on_delete=models.CASCADE为级联删除

ManyToManyField

多对多,models.ManyToManyField("Author")

EmailField

邮箱类型,底层继承 CharField

OneToOneField

OneToOneField = ForeignKey(...,unique=True)设置一对一

models.OneToOneField("AuthorDetail", on_delete=models.CASCADE)

SmallIntegerField

整数

字段选项

描述

null

True,表示空,默认False

blank

True,表示空白,默认False ,null是数据库范畴的概念,blank是表单验证范畴

db_column

字段的名称,如果未指定,则使用属性的名称(只限于数据库表中的名字,操作数据库还是类属性的名字)

db_index

True, 则在表中会为此字段创建索引,默认False

default

默认值,这可以是值或可调用对象,如果可调用,则每次创建新对象时都会调用它

primary_key

True,则该字段会成为模型的主键字段,默认False,一般作为AutoField的选项使用

unique

True, 这个字段在表中必须有唯一值,这个值不能重复,默认False

verbose_name

后台显示字段名

5)使用,在views.py中:

  • 模型类实例化对象,执行对象.save()
  • 通过 ORM objects 提供的方法来实现(推荐),其方法总结如下:

方法

用法描述

create

添加数据,Book.objects.create(title="test",price=20,publish="test",pub_date="2021-12-22")

all

查询所有内容,返回QuerySet 类型数据,类似于 list,里面是一个个模型类的对象,可用索引下标取出模型类的对象,Book.objects.all()

filter

查询符合条件的数据,返回QuerySet 类型数据,Book.objects.filter(pk=3)

注:pk=3的意思是主键primary key=3,相当于id=3

因为id在pycharm里有特殊含义,是看内存地址的内置函数id(),因此用pk。

filter 中运算符号只能使用等于号 = ,不能使用大于号 > ,小于号 < ,等等其他符号。

exclude

查询不符合条件的数据,返回QuerySet 类型数据,Book.objects.exclude(price=30)

get

查询符合条件的返回模型类的对象符合条件的对象只能为一个,如果符合筛选条件的对象超过了一个或者没有一个都会抛出错误,Book.objects.get(pk=5)

order_by

对查询结果进行排序返回QuerySet 类型数据,降序Book.objects.order_by("-price")

reverse

对查询结果进行反转返回QuerySet 类型数据,Book.objects.order_by("-price").reverse()

count

查询数据的数量返回的数据是整数Book.objects.filter(price=200).count()

first

返回所有数据的第一条返回的数据是模型类的对象也可以用索引下标 [0]Book.objects.first()

last

返回最后一条数据返回的数据是模型类的对象不能用索引下标 [-1],ORM 没有逆序索引Book.objects.last()

exists

判断查询的结果 QuerySet 列表里是否有数据,返回的数据类型是布尔, truefalse判断的数据类型只能为 QuerySet 类型数据,不能为整型和模型类的对象。

Book.objects.exists(),Book.objects.first().exists()

values

查询部分字段的数据返回QuerySet 类型数据,想要字段名和数据用 values

books = Book.objects.values("pk","price"), print(books[0]["price"]

type(books))

values_list

查询部分字段的数据返回QuerySet 类型数据,只想要数据用 values_list

books = models.Book.objects.values_list("price","publish")

print(books[0][0],type(books))

distinct

对数据进行去重,distinct() 一般是联合 values 或者 values_list 使用

Book.objects.values_list("publish").distinct()

delete

删除,模型类的对象.delete();推荐,QuerySet 类型数据.delete()。

Book.objects.filter(pk=8).first().delete()

Book.objects.filter(pk__in=[1,2]).delete()

Book.objects.all().delete()

save

修改,模型类的对象.属性 = 更改的属性值,模型类的对象.save()

books = models.Book.objects.filter(pk=7).first()

books.price = 400

books.save()

update

推荐,修改,QuerySet 类型数据.update(字段名=更改的数据)

Book.objects.filter(pk__in=[7,8]).update(price=888)

查询条件

描述

=

等于号

__in

区间,Book.objects.filter(price__in=[200,300])

__gt

大于号,Book.objects.filter(price__gt=200)

__gte

大于等于号,Book.objects.filter(price__gte=200)

__lt

小于号,Book.objects.filter(price__lt=300)

__lte

小于等于号,Book.objects.filter(price__lte=300)

__range

在……之间,左闭右闭区间,Book.objects.filter(price__range=[200,300])

__contains

包含,Book.objects.filter(title__contains="菜")

__icontains

不区分大小写的包含,Book.objects.filter(title__icontains="python")

__startswith

以指定字符开头,Book.objects.filter(title__startswith="菜")

__endswith

以指定字符结尾,Book.objects.filter(title__endswith="教程")

__year

DateField 数据类型的年份,Book.objects.filter(pub_date__year=2008)

__month

DateField 数据类型的月份,Book.objects.filter(pub_date__month=10)

__day 

DateField 数据类型的天数,Book.objects.filter(pub_date__day=01)

__week_day

DateField 数据类型的星期几,0-6表示周一到周天

Book.objects.filter(pub_date__week_day=4).count()

3. 分组和聚合查询

3.1 分组查询

annotate(*args,**kwargs)  分组函数,查看 每个出版社出版的最贵的一本书

Book.objects.values('publish').annotate(Min('price'))

  # < QuerySet[

  # {'publish': '北大出版社','price__min': Decimal('67.000')},

  # {'publish': '山西出版社','price__min': Decimal('34.000')},

  # {'publish': '河北出版社', 'price__min': Decimal('123.000')},

  # {'publish': '浙江出版社', 'price__min': Decimal('2.000')},

  # {'publish': '湖北出版社', 'price__min': Decimal('124.000')},

  # {'publish': '湖南出版社',price__min': Decimal('15.000')}

  # ] >

3.2 聚合查询

aggregate(*args,**kwargs)  聚合函数,求书籍的平均价

Book.objects.all().aggregate(Avg('price'))  #{'price__avg': 145.23076923076923}

4. Q和F查询

仅仅靠单一的关键字参数查询已经很难满足查询要求。为此Django提供了F和Q查询。

4.1 Q查询

Q多条件组合查询,Q查询条件和非Q查询条件混合使用注意,不包Q()的查询条件一点要放在Q(查询条件)后面。

Q()可以使ORM的fifter()方法支持, 多个查询条件,使用逻辑关系(&、|、~)包含、组合到一起进行多条件查询;

语法:

  • fifter(Q(查询条件1)| Q(查询条件2))
  • fifter(Q(查询条件1)& Q(查询条件2))
  • Fifter(Q(查询条件1)& ~Q(查询条件1))
  • fifter(Q(查询条件1)| Q(Q(查询条件2)& ~ Q(Q(查询条件3)& Q(查询条件4)))

用法1:

from django.db.models import F,Q

from app.models import Book  # from app import models  models.Book.objects.all()

Book.objects.filter(Q(title__icontains='伟')|Q(publish__contains='山西')).values('title')

用法2:

from django.db.models import F,Q

con = Q()

price_list = [34.00,60.00,100.00]

pub_date = [2008,2010,2020]

for index,value in price_list:

sql1 = Q()

sql1.connector = 'OR'

sql1.children.append('price',value)

con.add(sql1, 'AND')

for index,value in pub_date:

sql2 = Q()

sql2.connector = 'OR'

sql2.children.append('pub_date__year',value)

con.add(sql2, 'AND')

sql = Book.objects.using('bookinfo').filter(con).values('title','price')

4.2 F查询

F查询可以获取对象中的字段的属性(列),并对其进行操作。

from django.db.models import F,Q

Book.objects.all().update(price=F('price')+1)   #对图书馆里的每一本书的价格上调1块钱

5. 多表查询

多表模型建立如下:

关联管理器(对象调用):多对多(双向均有关联管理器);一对多(只有多的那个类的对象有关联管理器,即反向才有)。

语法格式:

正向:属性名

book_obj = models.Book.objects.get(id=10)

author_list = models.Author.objects.filter(id__gt=2)

book_obj.authors.add(*author_list)  #将id大于2的作者对象添加到这本书的作者集合中

# 方式二:传对象 id

book_obj.authors.add(*[1,3])  #将id=1和id=3的作者对象添加到这本书的作者集合中

反向:小写类名加 _set

ying = models.Author.objects.filter(name="任盈盈").first()

book = models.Book.objects.filter(title="冲灵剑法").first()

ying.book_set.add(book)

常用方法

描述

add()

用于多对多,把指定的模型对象添加到关联对象集(关系表)中,注:

add() 在一对多(即外键)中,只能传对象( *QuerySet数据类型),不能传 id(*[id表])

create()

创建一个新的对象,并同时将它添加到关联对象集之中,返回新创建的对象

remove()

从关联对象集中移除执行的模型对象,

对于 ForeignKey 对象,这个方法仅在 null=True(可以为空)时存在,无返回值。

clear()

从关联对象集中移除一切对象,删除关联,不会删除对象。

对于 ForeignKey 对象,这个方法仅在 null=True(可以为空)时存在,无返回值。

__lt

小于号,Book.objects.filter(price__lt=300)

__lte

小于等于号,Book.objects.filter(price__lte=300)

__range

在……之间,左闭右闭区间,Book.objects.filter(price__range=[200,300])

__contains

包含,Book.objects.filter(title__contains="菜")

__icontains

不区分大小写的包含,Book.objects.filter(title__icontains="python")

__startswith

以指定字符开头,Book.objects.filter(title__startswith="菜")

__endswith

以指定字符结尾,Book.objects.filter(title__endswith="教程")

__year

DateField 数据类型的年份,Book.objects.filter(pub_date__year=2008)

__month

DateField 数据类型的月份,Book.objects.filter(pub_date__month=10)

__day 

DateField 数据类型的天数,Book.objects.filter(pub_date__day=01)

__week_day

DateField 数据类型的星期几,0-6表示周一到周天

Book.objects.filter(pub_date__week_day=4).count()

5.1 正向查找

一对多:

res1 = models.Book.objects.filter(title='Python').values('publish__city')

print(res1)  #[{'publish__city': '北京'}]

多对多:

ret2 = models.Book.objects.filter(title='Python').values('author__name')

print(res2)

ret3 = models.Book.objects.filter(author__name="alex").values('title')

print(ret3)

正向查找的publish__city或者author__name中的publish,author是book表中绑定的字段

5.2 反向查找

一对多:

res4 = models.Publish.objects.filter(book__title='Python').values('name')

print(res4)  #[{'name': '人大出版社'}] book__title中的book就是Publish的关联表名

res5 = models.Publisher.objects.filter(book__title='Python').values('book__authors')

print(res5)  #[{'book__authors': 1}, {'book__authors': 2}]

多对多:

res6 = models.Author.objects.filter(book__title='Python').values('name')

print(res6) #[{'name': 'alex'}, {'name': 'alvin'}]

正向查找的book__title中的book是小写类名book

6.参考链接

菜鸟课程:Django ORM – 多表实例 | 菜鸟教程

博客园:Django之ORM查询操作详解 - 小帅帅呆了 - 博客园

博客园:Django ORM之F与Q查询 - 秋刀鱼的滋味w - 博客园

博客园:Django之ORM - 迎风而来 - 博客园

博客园:Django之ORM操作 - 张根 - 博客园

Django使用union合并:

Django 使用 union 合并不同模型(Model) 的查询集(QuerySet)_Django ORM 高级操作_追梦人物的博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值