开发工程师必备————【Day30】ORM查询补充知识点及多对多三种创建方式

今日内容概要

  • 正反向查询进阶操作
  • 聚合查询
  • 分组查询
  • F与Q查询
  • ORM查询优化
  • ORM常见字段类型
  • ORM常见字段参数
  • ORM事务操作
  • 多对多三种创建方式详解

正反向查询进阶操作

正反向查询进阶操作

  • 1.查询主键为1的书籍对应的出版社名称及书名
res = models.Publish.objects.filter(book__pk=1).values('name','book__title')
# print(res)
  • 2.查询主键为3的书籍对应的作者姓名及书名
res = models.Author.objects.filter(book__pk=1).values('name', 'book__title')
# print(res)
  • 3.查询jason的作者的电话号码和地址
res = models.AuthorDetail.objects.filter(author__name='jason').values('phone','addr')
# print(res)
  • 4.查询南方出版社出版的书籍名称和价格
res = models.Book.objects.filter(publish__name='南方出版社').values('title','price')
# print(res)
  • 5.查询jason写过的书的名称和日期
res = models.Book.objects.filter(authors__name='jason').values('title','publish_time')
# print(res)
  • 6.查询电话是110的作者姓名和年龄
res = models.Author.objects.filter(author_detail__phone=110).values('name','age')
# print(res)
  • 7.查询主键为1的书籍对应的作者电话号码
res = models.AuthorDetail.objects.filter(author__book__pk=1).values('phone')
# print(res)
res = models.Author.objects.filter(book__pk=1).values('author_detail__phone')
print(res)

聚合查询

1.聚合函数
max、min、sum、avg、count
2.聚合查询

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

# 没有分组之前如果单纯的时候聚合函数 需要关键字aggregate
res = models.Book.objects.aggregate(Max('price'), Min('price'), Sum('price'), Avg('price'), Count('pk'))
print(res)

分组查询

1.分组查询特性
(1)分组有一个特性,默认只能够直接获取分组的字段,其他字段需要使用方法;
(2)我们也可以忽略掉该特性,将sql_mode中only_full_group_by配置移除即可。

2.分组查询

  • 示例1:统计每一本书的作者个数
res = models.Book.objects.annotate(author_num=Count('authors__pk')).values('title', 'author_num')
print(res)
res1 = models.Book.objects.values('publish_id').annotate(book_num=Count('pk')).values('publish_id','book_num')
print(res1)

"""
   1.按照整条数据分组
       models.Book.objects.annotate()  按照一条条书籍记录分组
   2.按照表中某个字段分组()
       models.Book.objects.values('title').annotate()  按照annotate之前values括号>中指定的字段分组
"""
  • 示例2:统计出每个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')
print(res)
  • 示例3:统计不止一个作者的图书
    filter在annotate前面则是where 在annotate后面则是having
res = models.Book.objects.annotate(author_num=Count('authors__pk')).filter(author_num__gt=1).values('title','author_num')
print(res)
  • 示例4:查询各个作者出的书的总价格
res = models.Author.objects.annotate(book_sum_price = Sum('book__price')).values('name','book_sum_price')
print(res)

F与Q查询

1.补充
当表中已经有数据的情况下,添加新的字段需要指定一些参数:

  • 设置字段值允许为空
null = True
  • 设置字段默认值
default = 1000(默认值)
  • 在终端直接给出默认值
1 provide a default value

2.F查询
F查询:查询条件不是自定义的而是来自于表中其他字段
首先先导入模块:

from django.db.models import F
  • 1.查询库存数大于卖出数的书籍
res = models.Book.objects.filter(storage_num__gt=F('sale_num'))
print(res)
  • 2.将所有书籍的价格上涨1000块
models.Book.objects.update(price=F('price') + 1000)
  • 3.将所有书籍名称加上爆款后缀
models.Book.objects.filter(pk=5).update(title=F('title') + '爆款')  # 针对字符串数据无法直接拼接
会报错,需要再到一个模块!!!

from django.db.models.functions import Concat
from django.db.models import Value
ret3 = models.Book.objects.filter(pk=5).update(title=Concat(F('title'), Value('爆款')))

3.Q查询(可以改变filter括号内多个条件之间的逻辑运算符,还可以将查询条件的字段改为字符串形式)
filter() 等方法中逗号隔开的条件是与的关系。 如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象。

  • 你可以组合& 和| 操作符以及使用括号进行分组来编写任意复杂的Q 对象。
from django.db.models import Q
# 查询书籍名称是python入门或者价格是544.44的书
modelsBook.objects.filter(Q(title='python入门')|Q(price=544.44))
  • 同时,Q 对象可以使用" ~ "操作符取反,这允许组合正常的查询和取反(NOT/非) 查询。
# 查询书籍名称不是python入门或价格不是544.44的书
models.Book.objects.filter(~Q(title='python入门')|Q(price=54))
Q查询进阶
models.Book.objects.filter(Q(title="linux") | Q(price=123))
  • 上面的方式查询条件只能是字段名。如果我们只有字符串怎么写呢?
    查询条件由用户输入决定
q = Q()            # 实例化一个Q对象
q.connector = 'or'   #将默认and,改为or
q.children.append(('title','python'))
q.children.append(('kucun',666))
res = models.Book.objects.filter(q)

ORM查询优化

1.ORM查询特性
(1)django orm默认都是惰性查询
当orm的语句在后续的代码中真正需要使用的时候才会执行
(2)django orm自带limit分页
减轻数据库端以及服务端的压力

2.ORM表查询优化之only与defer

res = models.Book.objects.only('title','price')
for obj in res:
    print(obj.title)
    print(obj.price)
    print(obj.publish_time)
   """
   only会将括号内填写的字段封装成一个个数据对象 对象在点击的时候不会再走数据库查询
   但是对象也可以点击括号内没有的字段 只不过每次都会走数据库查询
   """
res = models.Book.objects.defer('title', 'price')
for obj in res:
   # print(obj.title)
   # print(obj.price)
   print(obj.publish_time)
   """
   defer与only刚好相反 
       数据对象点击括号内出现的字段 每次都会走数据库查询
       数据对象点击括号内没有的字典 不会走数据库查询
   """

3.ORM查询优化之select_related与prefetch_related

res = models.Book.objects.all()
for obj in res:
    print(obj.publi sh.name)  # 频繁走数据库查询

res = models.Book.objects.select_related('authors')
"""
   select_related括号内只能接收外键字段(一对多 一对一) 自动连表 得出的数据对象在点击表中数据的时候都不会再走数据库查询
   """
for obj in res:
    print(obj.publish.name)
"""
   prefetch_related底层其实是子查询 将查询之后的结果也一次性封装到数据对象中 用户在使用的时候是感觉不出来的
   """
res = models.Book.objects.prefetch_related('publish')
for obj in res:
   print(obj.publish.name)

事务操作

1.事务: ACID
2.事务隔离级别:
脏读 幻读 不可重复读 …
3.原生SQL:

start transaction\rollback\commit\savepoint

4.orm中使用事务
导入transaction模块。

from django.db import transaction
try:
   with transaction.atomic():
       pass  # 多条ORM语句
except Exception as e:
       print(e)

模型层常见字段

1.常见模型字段

1、models.AutoField  自增列= int(11)
  如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。
  
  
2、models.CharField  字符串字段
  必须 max_length 参数
  
3、models.BooleanField  布尔类型=tinyint(1)
  不能为空,Blank=True
  
4、models.ComaSeparatedIntegerField  用逗号分割的数字=varchar
  继承CharField,所以必须 max_lenght 参数
  
5、models.DateField  日期类型 date
  对于参数,auto_now =True则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。
  
6、models.DateTimeField  日期类型 datetime
  同DateField的参数
  
7、models.DecimalField  十进制小数类型= decimal
  必须指定整数位max_digits和小数位decimal_places
  
8、models.EmailField  字符串类型(正则表达式邮箱)=varchar
  对字符串进行正则表达式
  
9、models.FloatField  浮点类型= double

10、models.IntegerField  整形

11、models.BigIntegerField  长整形
  integer_field_ranges ={
    'SmallIntegerField':(-32768,32767),
    'IntegerField':(-2147483648,2147483647),
    'BigIntegerField':(-9223372036854775808,9223372036854775807),
    'PositiveSmallIntegerField':(0,32767),
    'PositiveIntegerField':(0,2147483647),
  }
  
12、models.IPAddressField  字符串类型(ip4正则表达式)

13、models.GenericIPAddressField  字符串类型(ip4和ip6是可选的)
  参数protocol可以是:both、ipv4、ipv6
  验证时,会根据设置报错
  
14、models.NullBooleanField  允许为空的布尔类型

15、models.PositiveIntegerFiel  正Integer

16、models.PositiveSmallIntegerField  正smallInteger

17、models.SlugField  减号、下划线、字母、数字

18、models.SmallIntegerField  数字
  数据库中的字段有:tinyint、smallint、int、bigint
  
19、models.TextField  字符串=longtext

20、models.TimeField  时间 HH:MM[:ss[.uuuuuu]]

21、models.URLField  字符串,地址正则表达式

22、models.BinaryField  二进制

23、models.ImageField  图片

24、models.FilePathField  文件

2.ORM还支持自定义字段
自定义char字段

from django.db import models

#Django中没有对应的char类型字段,但是我们可以自己创建
class MyCharField(models.Field):
   '''
   自定义的char类型的字段类
   '''
   def __init__(self,max_length,*args,**kwargs):
       self.max_length=max_length
       super().__init__(max_length=max_length,*args,**kwargs)

   def db_type(self, connection):
       '''
       限定生成的数据库表字段类型char,长度为max_length指定的值
       :param connection:
       :return:
       '''
       return 'char(%s)'%self.max_length

3.ORM字段与MySQL字段对应关系:

'AutoField': 'integer AUTO_INCREMENT',
'BigAutoField': 'bigint AUTO_INCREMENT',
'BinaryField': 'longblob',
'BooleanField': 'bool',
'CharField': 'varchar(%(max_length)s)',
'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
'DateField': 'date',
'DateTimeField': 'datetime',
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
'DurationField': 'bigint',
'FileField': 'varchar(%(max_length)s)',
'FilePathField': 'varchar(%(max_length)s)',
'FloatField': 'double precision',
'IntegerField': 'integer',
'BigIntegerField': 'bigint',
'IPAddressField': 'char(15)',
'GenericIPAddressField': 'char(39)',
'NullBooleanField': 'bool',
'OneToOneField': 'integer',
'PositiveIntegerField': 'integer UNSIGNED',
'PositiveSmallIntegerField': 'smallint UNSIGNED',
'SlugField': 'varchar(%(max_length)s)',
'SmallIntegerField': 'smallint',
'TextField': 'longtext',
'TimeField': 'time',
'UUIDField': 'char(32)',

ORM常见字段参数

1.常见字段参数

1、null=True
  数据库中字段是否可以为空
  
2、blank=True
  django的Admin中添加数据时是否可允许空值
  
3、primary_key =False
  主键,对AutoField设置主键后,就会代替原来的自增 id 列
  
4、auto_now 和 auto_now_add
  auto_now 自动创建---无论添加或修改,都是当前操作的时间
  auto_now_add 自动创建---永远是创建时的时间
  
5、choices
GENDER_CHOICE =(
(u'M', u'Male'),
(u'F', u'Female'),
) 
gender = models.CharField(max_length=2,choices = >GENDER_CHOICE)  #字段模板展示

6、max_length  最大长度

7、default  默认值

8、verbose_name  Admin中字段的显示名称

9、name|db_column  数据库中的字段名称

10、unique=True  不允许重复

11、db_index =True  数据库索引

12、editable=True  在Admin里是否可编辑

13、error_messages=None  错误提示

14、auto_created=False  自动创建

15、help_text  在Admin中提示帮助信息

16、validators=[]  验证器

17、upload-to    重定义上传文件的路径前缀

18.choices
	当字段数据的可能性是可以完全列举出来的时候 应该考虑使用该参数
   	性别
   	学历
   	成绩  
```python       
	class UserInfo(models.Model):
       username = models.CharField(max_length=32)
       gender_choice = (
           (1, '男性'),
           (2, '女性'),
           (3, '其他'),
       )
       gender = models.IntegerField(choices=gender_choice)
	userinfo_obj.get_gender_display()

2.外键字段相关参数

to        # 设置要关联的表
to_field    # 设置要关联的表的字段
related_name    # 改变正反向查询
on_delete   # 级联删除

3.设置级联相关的操作

   1、models.CASCADE
       级联操作,当主表中被连接的一条数据删除时,从表中所有与之关联的数据同时被删除
   2、models.SET_NULL
       当主表中的一行数据删除时,从表中所有与之关联的数据的相关字段设置为null,此时注意定义外键时,这个字段必须可以允许为空
   3、models.PROTECT
       当主表中的一行数据删除时,由于从表中相关字段是受保护的外键,所以都不允许删除
   4、models.SET_DEFAULT
       当主表中的一行数据删除时,从表中所有相关的数据的关联字段设置为默认值,此时注意定义外键时,这个外键字段应该有一个默认值
   5、models.SET()
       当主表中的一条数据删除时,从表中所有的关联数据字段设置为SET()中设置的值,与models.SET_DEFAULT相似,只不过此时从表中的相关字段不需要设置default参数
   6、models.DO_NOTHING
       什么都不做,一切都看数据库级别的约束,注数据库级别的默认约束为RESTRICT,这个约束与django中的models.PROTECT相似

多对多三种创建方式

1.自动创建

authors = models.ManyToManyField(to='Author')

	优点:第三张表自动创建
	缺点:第三张表扩展性差

2.2.手动创建

class Book(models.Model):
     pass
class Author(models.Model):
     pass
class Book2Author(models.Model):
     book_id = models.ForeignKey(to="Book")
      author_id = models.ForeignKey(to="Author")
      
	优点:第三张表扩展性强
 	缺点:无法使用正反向查询以及多对多四个方法(add;remove,等)

3.半自动创建

class Book(models.Model):
    authors = models.ManyToManyField(to='Author',
                  through='Book2Author'
                  through_fields=('book_id','author_id')
                                    )
class Author(models.Model):
     pass
class Book2Author(models.Model):
     book_id = models.ForeignKey(to="Book")
     author_id = models.ForeignKey(to="Author")
       
  	优点:扩展性强并且支持正反向查询
 	 缺点:无法使用多对多四个方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值