[TOC]
基于双下划线的连表查询
from django.db import models
# Create your models here.
class Author(models.Model):
"""
作者表
"""
name=models.CharField( max_length=32)
age=models.IntegerField()
# authorDetail=models.OneToOneField(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE) #
auth=models.OneToOneField("AuthorDetail",on_delete=models.CASCADE)
class AuthorDetail(models.Model):
"""
作者详细信息表
"""
birthday=models.DateField()
telephone=models.CharField(max_length=11)
addr=models.CharField(max_length=64)
# class Meta:
# db_table='authordetail' #指定表名
# ordering = ['-id',]
class Publish(models.Model):
"""
出版社表
"""
name=models.CharField( max_length=32)
city=models.CharField( max_length=32)
class Book(models.Model):
"""
书籍表
"""
title = models.CharField( max_length=32)
publishDate=models.DateField()
price=models.DecimalField(max_digits=5,decimal_places=2)
pub=models.ForeignKey(to="Publish",on_delete=models.CASCADE,)
authors=models.ManyToManyField('Author',)
一对一:
# 查询alex的电话号码
正向:依靠属性
ret = models.Author.objects.filter(name='alex').values('auth__telephone')
# <QuerySet [{'auth__telephone': '110'}]>
反向:依靠类名(表名)小写
ret = models.AuthorDetail.objects.filter(author__name='alex').values('telephone')
# <QuerySet [{'telephone': '110'}]>
print(ret)
多对一:
# 查询一下 xxx 这本书的出版社
# 正向:依靠属性
ret=models.Book.objects.filter(title='xxx').values('pub__name')
# <QuerySet [{'pub__name': '人民出版社'}]>
# 反向:依靠类名(表名)小写
ret=models.Publish.objects.filter(book__title='xxx').values('name')
# <QuerySet [{'name': '人民出版社'}]>
# 查询 24期出版社 出版了那些书
# 反向
ret=models.Publish.objects.filter(name='24期出版社').values('book__title')
# <QuerySet [{'book__title': 'alex与meet的爱恨'}, {'book__title': '那年的24期'}]>
# 正向
ret=models.Book.objects.filter(pub__name='24期出版社').values('title')
# <QuerySet [{'title': 'alex与meet的爱恨'}, {'title': '那年的24期'}]>
多对多:
# xxx 这本书 是有哪些作者写的
# 正向查询:属性
ret=models.Book.objects.filter(title='xxx').values('authors__name')
# <QuerySet [{'authors__name': 'alex'}, {'authors__name': 'meet'}, {'authors__name': 'liu'}]>
"""
原生sql语句:
select app01_author.name from app01_book INNER JOIN app01_book_authors on app01_book.id = app01_book_authors.book_id
INNER JOIN app01_author on app01_book_authors.author_id = app01_author.id
where app01_book.title='xxx;
"""
# 反向查询:类名(表名)
ret=models.Author.objects.filter(book__title='xxx').values('name')
# <QuerySet [{'name': 'alex'}, {'name': 'meet'}, {'name': 'liu'}]>
related_name
反向查询,替代 表名小写 或者 表名_set 。必须替代,否则会报错。
pub = ForeignKey(Publish, related_name='bookList')
ret=models.Book.objects.filter(title='xxx').values('bookList__name')
聚合查询 aggregate
# 统计书的平均价格以及最高价格
from django.db.models import Avg, Max
ret = models.Book.objects.all().aggregate(Avg('price'),Max('price')) # 结果是python字典, 也就是说聚合查询是orm的结束语句,一般放在最后.
# {'price__avg': 137.833333, 'price__max': Decimal('222.00')}
ret = models.Book.objects.all().aggregate(a=Avg('price'),m=Max('price'))
# 给键取名字
{'a': 137.833333, 'm': Decimal('222.00')}
分组查询 annotate
必须起别名。
# 每个出版社的书的平均价格
models.Book.objects.values('pub__id').annotate(a=Avg('price'))
# 按属性pub分组(按publish表的id分组)
# <QuerySet [{'pub__id': 1, 'a': 186.0}, {'pub__id': 2, 'a': 100.0}, {'pub__id': 3, 'a': 5.0}, {'pub__id': 4, 'a': 175.0}]>
models.Book.objects.values('pub_id').annotate(a=Avg('price'))
# 按book表的pub_id字段分组
# <QuerySet [{'pub_id': 1, 'a': 186.0}, {'pub_id': 2, 'a': 100.0}, {'pub_id': 3, 'a': 5.0}, {'pub_id': 4, 'a': 175.0}]>
models.Publish.objects.annotate(a=Aug('book__price')).values('a')
# 连表后拿Publish的id进行分组,a是别名
<QuerySet [{'a': 186.0}, {'a': 100.0}, {'a': 5.0}, {'a': 175.0}]>
F查询--锁定本表字段
本表字段中,要对两个字段的值做比较,F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。
from django.db.models import F
ret = models.Book.objects.filter(字段1__gt=F('字段2'))
# 查询book表中 字段1 大于 字段2的记录
django支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。
修改操作也可以使用F函数。
# 将所有书籍价格提高10
models.Book.objects.all().update(
price=F('price')+10
)
Q查询 -- 或 | 、与 & 、非 ~
注意:, 是 AND查询
from django.db.models import Q
# 查询书籍价格大于200或者价格小于100
models.Book.objects.filter(Q(price__gt=200)|Q(price__lt=100))
可以多层嵌套
Q(Q(price__gt=200)|Q(price__lt=100))|Q(...)
与关键字参数一起使用,Q
对象必须位于所有关键字参数的前面。
查询书籍价格大于200或者价格小于100并且id=2
models.Book.objects.filter(Q(price__gt=200)|Q(price__lt=100),id=2)
作业:
1 查询每个作者的姓名以及出版的书的最高价格
ret=models.Author.objects.annotate(max=Max('book__price')).values('name', 'max')
print(ret)
2 查询作者id大于2作者的姓名以及出版的书的最高价格
ret = models.Author.objects.filter(id__gt=2).annotate(max=Max('book__price')).values('name', 'max')
3 查询作者id大于2或者作者年龄大于等于20岁的作者的姓名以及出版的书的最高价格
ret = models.Author.objects.filter(Q(id__gt=2)|Q(age__gte=20)).annotate(max=Max('book__price')).values('name', 'max')
4 查询每个作者出版的书的最高价格 的平均值
ret = models.Author.objects.annotate(max=Max('book__price')).aggregate(Avg('max'))
5 每个作者出版的所有书的最高价格以及最高价格的那本书的名称
select title,price from (select app01_author.id,app01_book.title,app01_book.price from app01_author INNER JOIN app01_book_authors on app01_author.id=
app01_book_authors.author_id INNER JOIN app01_book on app01_book.id=
app01_book_authors.book_id ORDER BY app01_book.price desc) as b GROUP BY id;
ORM执行原生sql语句
在模型查询API(接口)不够用的情况下,我们还可以使用原始的SQL语句进行查询。
Django 提供两种方法使用原始SQL进行查询:一种是使用raw()方法,进行原始SQL查询并返回模型实例;另一种是完全避开模型层,直接执行自定义的SQL语句。
执行原生查询
raw()管理器方法用于原始的SQL查询,并返回模型的实例:
raw()语法查询必须包含主键。
返回一个RawQuerySet对象
models.Book.objects.raw('select price from app01_book where id=2')
直接执行自定义SQL
from django.db import connection, connections
cursor = connection.cursor() # cursor = connections['default'].cursor()
cursor.execute('SELECT * from auth_user where id = %s', [1])
ret = cursor.fetchone()
Python脚本中调用Django环境(django外部脚本使用models)
如果你想通过自己创建的python文件在django项目中使用django的models,那么就需要调用django的环境:
import os
if __name__ == '__main__':
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
import django
django.setup()
from app01 import models #引入也要写在上面三句之后
books = models.Book.objects.all()
print(books)
事务与锁
Django orm中的锁
models.Book.objects.select_for_update().filter(id=1) # 给id=1的行级加锁
事务开启
1. 全局开启
整个视图函数中,统一个http请求对应的所有sql都放在一个事务中执行(要么所有都成功,要么所有都失败)。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'orm',
'HOST': '127.0.0.1',
'PORT': '3306',
'USER': 'root',
'PASSWORD': '123',
"ATOMIC_REQUESTS": True, #全局开启事务,绑定的是http请求响应整个过程
}
2. 局部开启
atomic(using=None, savepoint=True)[source]
原子性是数据库事务的一个属性。使用atomic,我们就可以创建一个具备原子性的代码块。一旦代码块正常运行完毕,所有的修改会被提交到数据库。反之,如果有异常,更改会被回滚。
被atomic管理起来的代码块还可以内嵌到方法中。这样的话,即便内部代码块正常运行,如果外部代码块抛出异常的话,它也没有办法把它的修改提交到数据库中。
方式1:给函数做装饰器来使用
from django.db import transaction
@transaction.atomic
def viewfunc(request):
# This code executes inside a transaction.
do_stuff()
方式2: 作为上下文管理器来使用,其实就是设置事务的保存点
(给某一视图函数中部分sql语句加锁)
def viewfunc(request):
do_stuff()
with transaction.atomic(): # 设置保存点
pass