Django ORM相关操作

官方文档:

https://docs.djangoproject.com/en/2.0/ref/models/querysets/

1.必须掌握的十三个方法

<1> all()                 查询所有结果

<2> filter(**kwargs)      它包含了与所给筛选条件相匹配的对象

<3> get(**kwargs)         返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一
                个或者没有都会抛出错误 <4> exclude(**kwargs) 它包含了与所给筛选条件不匹配的对象 <5> values(*field) 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实
               例化对象,而是一个可迭代的字典序列 <6> values_list(*field) 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列 <7> order_by(*field) 对查询结果排序 <8> reverse() 对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用
                (在model类的Meta中指定ordering或调用order_by()方法) <9> distinct() 从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果
                此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重) <10> count() 返回数据库中匹配查询(QuerySet)的对象数量 <11> first() 返回第一条记录 <12> last() 返回最后一条记录 <13> exists() 如果QuerySet包含数据,就返回True,否则返回False

  分类:

    1)返回QuerySet对象的方法

all()
filter()
exclude()
order_by()
reverse()
distinct()
values()
values_list()

    2)返回具体对象

get()
first()
last()

    3)返回布尔值

exists()

    4)返回数字的方法

count()

2.ForeignKey,外键

示例:

from django.db import models

# Create your models here.
# 书
class Book(models.Model):
title = models.CharField(max_length=32)
publish_date = models.DateField(auto_now_add=True)
price = models.DecimalField(max_digits=5, decimal_places=2)
memo = models.TextField(null=True)
# 创建外键,关联publish
publisher = models.ForeignKey(to="Publisher", on_delete=models.CASCADE, related_name='books')
# 创建多对多关联author
author = models.ManyToManyField(to="Author") def __str__(self):
return self.title # 出版社
class Publisher(models.Model):
name = models.CharField(max_length=32)
city = models.CharField(max_length=32) def __str__(self):
return self.name # 作者
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
phone = models.CharField(max_length=11)
detail = models.OneToOneField(to="AuthorDetail", on_delete=models.CASCADE) def __str__(self):
return self.name # 作者详情
class AuthorDetail(models.Model):
addr = models.CharField(max_length=64)
email = models.EmailField()

模型

说明:

  因为建立每个模型也就是新建类的时候调用了__str__方法,所以通过类实例出对象时,默认返回该对象中指定的属性值  

  1)正向查找

  对象查找---跨表查找

语法:  
  对象.关联字段.字段
# 获取书名为"七侠五义"的对象
obj = models.Book.objects.get(title='七侠五义')
# 书籍和出版社间通关外键建立联表关系,可通过书籍对象跨表查询得到出版社的对象
print(obj.publisher)
# 得到出版社对象的名称
print(obj.publisher.name)

  字段查找---跨表查找

语法:
关联字段__字段
# 通过书籍对象获取对应出版社的名称和地址
ret = models.Book.objects.filter(title='七侠五义').values('publisher__name','publisher__city')
print(ret)

  2)反向操作

  对象查找

语法:
  对象.表名_set
# 获取出版社的名称
obj = models.Publisher.objects.get(name='南方传媒出版社')
# 反向获取该出版社下的书籍
books = obj.book_set.all()
print(books)

  字段查找

语法:
表名__字段
# 反向获出版社下的书籍
ret = models.Publisher.objects.filter(name='南方传媒出版社').values('books__title')
print(ret)

3.ManyToManyField,多对多

  关联管理器是在一对多或者多对多的关联上下文中是使用的管理器

  存在两种情况:

    A.外键关系的反向查询

    B.多对多关联关系

  简单的说就是当点后面的对象---(针对对象操作)可能存在多个的时候就可以使用以下方法:

  create(),创建一个新对象,保存对象,并将它添加到关联对象集之中,返回新建的对象

import datetime
# 通过获取到的第一个作者新建一个书籍对象
models.Author.objects.first().book_set.create(title='黑鹰传奇',
                            publish_date=datetime.date.today(),
                            price=100, publisher_id=1)

  add(),把指定的model对象添加到关联的对象中

author_objs = models.Author.objects.filter(id__gt=2)
print(author_objs)
print(*author_objs)
# 获取书籍对象,通过*打散获取到的QuerySet添加到书籍对象中
models.Book.objects.get(title='七侠五义').author.add(*author_objs)

  添加ID

models.Book.objects.get(title='黑影传奇').author.add(*[3, 4, 7])

  set(),更新model对象的关联对象

models.Book.objects.get(title='黑影传奇').author.set([3, 4])

  remove(),从关联对象中移除

models.Book.objects.get(title='黑影传奇').author.remove(*[3, 4])

  clear(),将关联的对象清除

models.Book.objects.get(title='黑影传奇').author.clear()

强调:

  A.对于ForeignKey对象,clear()和remove()方法仅在null=True时才存在

示例:

  不存在null=True时,没有clear()和remove()方法:

models.Publisher.objects.first().book_set.clear()
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'RelatedManager' object has no attribute 'clear'

  B.对于所有类型的关联字段,add()、create()、remove()和clear(),set()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法

4.聚合查询和分组查询

  1)聚合

  aggregate()是QuerySet的一个终止句子,意思是说它返回一个包含键值对的字典,键的名称是聚合值的标识符,值是计算出来的聚合值,键的名称是按照字段和聚合函数的名称自动生成出来的

  涉及到的内置函数

from django.db.models import Avg, Sum, Max, Min, Count

示例:

from django.db.models import Avg, Sum, Max, Min, Count
ret1 = models.Book.objects.all().aggregate(Avg('price'))
# 为聚合句子起别名
ret2 = models.Book.objects.all().aggregate(avg_price=Avg('price'))
# 在句子中添加多个参数生成多个聚合
ret3 = models.Book.objects.all().aggregate(avg_price=Avg('price'),max_price=Max('price'))

  2)分组

# 按照书籍分组,求出书籍作者的个数
ret = models.Book.objects.annotate(count=Count('author')).values('title','count')

5.F查询和Q查询

from django.db import models

# Create your models here.
class Product(models.Model):
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=6,decimal_places=2) # 商品库存数
stock = models.IntegerField()
# 卖出数量
sell = models.IntegerField() def __str__(self):
return "{}:{}:{}:{}".format(self.name self.price,self.stock,self.sell)

  

  1)F查询

  在之前的例子中,所构造出的过滤器只是将字段值与某个常量进行比较,如果要对两个字段的值进行比较,需要通过F(),F()实例可以在查询中引用字段,用来比较同一个model实例中两个不同字段的值

示例:

from django.db.models import F
# 查询商品库存大于卖出数的
ret = models.Product.objects.filter(stock__gt=F('sell')).values('name','stock','sell')

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

# 查询卖出商品数小于库存一半的商品
ret = models.Product.objects.filter(sell__lt=F('stock')/2).values('name','stock','sell')

  同时可以通过F()方法进行修改操作

# 修改操作---整型字段
ret = models.Product.objects.filter(name='七侠五义').update(sell=F('sell')+50)
# 修改操作---char字段
from django.db.models.functions import Concat
from django.db.models import Value
ret = models.Product.objects.filter(name='七侠五义').update(name=Concat(F('name'),
                                          Value("(完整版)")))

  2)Q查询

  filter()等方法中的关键字查询都是一起进行与操作的,当需要复杂的操作如或等操作时需要用到Q()

示例:

# 查找库存和卖出的数量都大于四百的书籍
from django.db.models import Q
ret = models.Product.objects.filter(Q(stock__gt=400) & Q(sell__gt=400))

  查询函数可以将Q()和关键字参数混合使用,所有提供查询函数的参数(关键字参数或Q()对象)都将进行与运算,但是如果出现Q()对象,必须位于所有关键字参数的前面

# 查找出名字带有"传奇"以及价钱大于100的书籍
ret = models.Product.objects.filter(Q(price__gt=100),name__contains='传奇')

6.事务

  一般用于错误回滚

# 用于错误回滚
try:
from django.db import transaction with transaction.atomic(): create_book = models.Product.objects.create(name="七剑下天山", price=98, stock=100, sell=80)
models.Product.objects.create()
except Exception as e:
print(str(e))

附:

  其他不常用操作

# extra
# 在QuerySet的基础上继续执行子语句
# extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None) # select和select_params是一组,where和params是一组,tables用来设置from哪个表
# Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
# Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
# Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
# Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid']) 举个例子:
models.UserInfo.objects.extra(
select={'newid':'select count(1) from app01_usertype where id>%s'},
select_params=[1,],
where = ['age>%s'],
params=[18,],
order_by=['-age'],
tables=['app01_usertype']
)
"""
select
app01_userinfo.id,
(select count(1) from app01_usertype where id>1) as newid
from app01_userinfo,app01_usertype
where
app01_userinfo.age > 18
order by
app01_userinfo.age desc
""" # 执行原生SQL
# 更高灵活度的方式执行原生SQL语句
# from django.db import connection, connections
# cursor = connection.cursor() # cursor = connections['default'].cursor()
# cursor.execute("""SELECT * from auth_user where id = %s""", [1])
# row = cursor.fetchone()

  在Django项目的setting.py添加日志功能

示例:在终端中打印日志信息

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

  在Python脚本上调用Django环境

import os

if __name__ == '__main__':
# 配置环境变量
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
# 导入Django
import django
# 启动Django
django.setup() # 导入模型
from app import models # ORM语句

总结:

   QuerySet方法大全

##################################################################
# PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET #
################################################################## def all(self)
# 获取所有的数据对象 def filter(self, *args, **kwargs)
# 条件查询
# 条件可以是:参数,字典,Q def exclude(self, *args, **kwargs)
# 条件查询
# 条件可以是:参数,字典,Q def select_related(self, *fields)
性能相关:表之间进行join连表操作,一次性获取关联的数据。 总结:
1. select_related主要针一对一和多对一关系进行优化。
2. select_related使用SQL的JOIN语句进行优化,通过减少SQL查询的次数来进行优化、提高性能。 def prefetch_related(self, *lookups)
性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。 总结:
1. 对于多对多字段(ManyToManyField)和一对多字段,可以使用prefetch_related()来进行优化。
2. prefetch_related()的优化方式是分别查询每个表,然后用Python处理他们之间的关系。 def annotate(self, *args, **kwargs)
# 用于实现聚合group by查询 from django.db.models import Count, Avg, Max, Min, Sum v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))
# SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)
# SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1 v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)
# SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1 def distinct(self, *field_names)
# 用于distinct去重
models.UserInfo.objects.values('nid').distinct()
# select distinct nid from userinfo 注:只有在PostgreSQL中才能使用distinct进行去重 def order_by(self, *field_names)
# 用于排序
models.UserInfo.objects.all().order_by('-id','age') def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
# 构造额外的查询条件或者映射,如:子查询 Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid']) def reverse(self):
# 倒序
models.UserInfo.objects.all().order_by('-nid').reverse()
# 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序 def defer(self, *fields):
models.UserInfo.objects.defer('username','id')

models.UserInfo.objects.filter(...).defer('username','id')
#映射中排除某列数据 def only(self, *fields):
#仅取某个表中的数据
models.UserInfo.objects.only('username','id')

models.UserInfo.objects.filter(...).only('username','id') def using(self, alias):
指定使用的数据库,参数为别名(setting中的设置) ##################################################
# PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
################################################## def raw(self, raw_query, params=None, translations=None, using=None):
# 执行原生SQL
models.UserInfo.objects.raw('select * from userinfo') # 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名
models.UserInfo.objects.raw('select id as nid from 其他表') # 为原生SQL设置参数
models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,]) # 将获取的到列名转换为指定列名
name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
Person.objects.raw('SELECT * FROM some_other_table', translations=name_map) # 指定数据库
models.UserInfo.objects.raw('select * from userinfo', using="default") ################### 原生SQL ###################
from django.db import connection, connections
cursor = connection.cursor() # cursor = connections['default'].cursor()
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
row = cursor.fetchone() # fetchall()/fetchmany(..) def values(self, *fields):
# 获取每行数据为字典格式 def values_list(self, *fields, **kwargs):
# 获取每行数据为元祖 def dates(self, field_name, kind, order='ASC'):
# 根据时间进行某一部分进行去重查找并截取指定内容
# kind只能是:"year"(年), "month"(年-月), "day"(年-月-日)
# order只能是:"ASC" "DESC"
# 并获取转换后的时间
- year : 年-01-01
- month: 年-月-01
- day : 年-月-日 models.DatePlus.objects.dates('ctime','day','DESC') def datetimes(self, field_name, kind, order='ASC', tzinfo=None):
# 根据时间进行某一部分进行去重查找并截取指定内容,将时间转换为指定时区时间
# kind只能是 "year", "month", "day", "hour", "minute", "second"
# order只能是:"ASC" "DESC"
# tzinfo时区对象
models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC)
models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai')) """
pip3 install pytz
import pytz
pytz.all_timezones
pytz.timezone(‘Asia/Shanghai’)
""" def none(self):
# 空QuerySet对象 ####################################
# METHODS THAT DO DATABASE QUERIES #
#################################### def aggregate(self, *args, **kwargs):
# 聚合函数,获取字典类型聚合结果
from django.db.models import Count, Avg, Max, Min, Sum
result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid'))
===> {'k': 3, 'n': 4} def count(self):
# 获取个数 def get(self, *args, **kwargs):
# 获取单个对象 def create(self, **kwargs):
# 创建对象 def bulk_create(self, objs, batch_size=None):
# 批量插入
# batch_size表示一次插入的个数
objs = [
models.DDD(name='r11'),
models.DDD(name='r22')
]
models.DDD.objects.bulk_create(objs, 10) def get_or_create(self, defaults=None, **kwargs):
# 如果存在,则获取,否则,创建
# defaults 指定创建时,其他字段的值
obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '','u_id': 2, 't_id': 2}) def update_or_create(self, defaults=None, **kwargs):
# 如果存在,则更新,否则,创建
# defaults 指定创建时或更新时的其他字段
obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '','u_id': 2, 't_id': 1}) def first(self):
# 获取第一个 def last(self):
# 获取最后一个 def in_bulk(self, id_list=None):
# 根据主键ID进行查找
id_list = [11,21,31]
models.DDD.objects.in_bulk(id_list) def delete(self):
# 删除 def update(self, **kwargs):
# 更新 def exists(self):
# 是否有结果

QuerySet方法大全

Django框架详细介绍---ORM相关操作的更多相关文章

  1. Django框架详细介绍---ORM相关操作---select_related和prefetch_related函数对 QuerySet 查询的优化

    Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化 引言 在数据库存在外键的其情况下,使用select_related()和pre ...

  2. Django框架详细介绍---模型---ORM

    一.概述 ORM(Object Relational Mapping),全称:对象关系映射,简单的说就是通过创建类.实例化出对象的方法,使得类.对象.对象的属性能够和数据库中的表.记录.字段意义对应. ...

  3. Django框架详细介绍---中间件(认证)

    一.绪论 在cookie和session的应用中,通过在视图函数内添加装饰器判断用户是否登录,把没有登录的用户请求跳转到登录页面,通过给几个特定视图函数加装饰器实现了这个需求.但是以后添加的视图函数可 ...

  4. Django框架详细介绍---cookie、session、自定义分页

    1.cookie 在HTTP协议介绍中提到,该协议是无状态的,也就是每次请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,它不会受前面的请求响应情况直接影响,也不会直接影响后面的 ...

  5. Django框架详细介绍---视图系统

    Django视图系统 1.什么是视图 在Django中,一个视图函数/类,称为视图.实质就是一个用户自定义的简单函数,用来接收WEB请求并xing响应请求,响应的内容可以是一个HTML文件.重定向.一 ...

  6. Django框架详细介绍---Admin后台管理

    1.Admin组件使用 Django内集成了web管理工具,Django在启动过程中会执行setting.py文件,初始化Django内置组件.注册APP.添加环境变量等 # Application ...

  7. Django框架详细介绍---请求流程

    Django请求流程图 1.客户端发送请求 2.wsgiref是Django封装的套接字,它将客户端发送过来的请求(请求头.请求体封装成request) 1)解析请求数据 2)封装响应数据 3.中间件 ...

  8. Django框架详细介绍---request对象

    几个重要的函数 1.HttpRequest.get_host() 根据从HTTP_X_FORWARDED_HOST(如果打开 USE_X_FORWARDED_HOST,默认为False和 HTTP_H ...

  9. Django框架详细介绍---认证系统

    在web开发中通常设计网站的登录认证.注册等功能,Django恰好内置了功能完善的用户认证系统 1.auth模块 from django.contrib import auth 模块源码 import ...

随机推荐

  1. MySQL 全文检索 ngram Mybatis

    创建全文索引(FullText index) 创建表的同时创建全文索引 FULLTEXT (name) WITH PARSER ngram 通过 alter table 的方式来添加 alter ta ...

  2. Linux 访问权限

    [TOC] Linux访问权限 Linux用户和用户组 查看当前用户用命令who am i 用命令id username可以显示指定用户的用户id.用户组id(GID).和所属附加群组的信息. 所有的 ...

  3. 【Android Studio】Gradle配置及问题解决

    Error:Failed to open zip file.Gradle's dependency cache may be corrupt (this sometimes occurs after ...

  4. classmethod作用

    >>> class A(object): bar = 1 def func1(self): print 'foo' >>> class A(object): bar ...

  5. 写在开始前---web异常处理

    分层项目中,有上层调用下层,每一层都可能出错,比如数据库连接,文件读写等异常.除了运行时程序的异常,还有业务逻辑的一些问题.发生异常需要做一定处理,既要让开发人员便于排查问题,又要让用户看到友好又便于 ...

  6. 【Zookeeper系列】ZooKeeper机制架构(转)

    原文链接:https://www.cnblogs.com/sunddenly/p/4133784.html 一.ZooKeeper权限管理机制 1.1 权限管理ACL(Access Control L ...

  7. Keil不能跳转到函数的定义怎么办

    有时候我们右键一个函数名并点击Go To Definition Of xxx时,Keil却提示无法找到定义.但这个函数确实有定义的.这个时候可以试着重新编译整个工程,即可跳转到定义了.

  8. Python Pandas 箱线图

    各国家用户消费分布 import numpy as np import pandas as pd import matplotlib.pyplot as plt data = { 'China': [ ...

  9. 创建dblink

    创建dblinkcreate database link user1_Link_app--dblink名称----connect to ehl_app ----远程数据库名称----identifie ...

  10. Educational Codeforces Round 1

    598A - Tricky Sum    20171103$$ans=\frac{n(n+1)}{2} - 2\sum_{k=0}^{\left \lfloor \log_2 n \right \rf ...