09 Django -- ORM 双下划线查询

基于双下划线的连表查询

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'}]>

反向查询,替代 表名小写 或者 表名_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的环境:

[复制代码](javascript:void(0)😉

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
    

posted @ 2019-10-14 21:55  SensorError  阅读(284)  评论(0编辑  收藏  举报