62 Django

Stella981
• 阅读 644

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

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

62 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
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这