Django 06

今日内容详细

一、正反向查询进阶操作

  正反向查询进阶操作

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=3).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(author__name='jason').values('title','publish_time')
print(res)

6.查询电话是110的作者姓名和年龄

res = models.Author.objects.filter(author_detil__phone=110).values('name','age')
print(res)

7.查询主键为1的书籍对应的作者电话号码

res = models.Author.objects.filter(book__pk=1).values('author_detail__phone')

res = models.Author_detail.objects.filter(author__book__pk=1).values('phone')

 

二、聚合查询

  聚合函数max、min、sum、avg、count

    '''  聚合查询 '''     (先导入模块才可以使用)

    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('price'))
    print(res)

 

三、分组查询

 """

    分组有一个特性,默认只能够直接获取分组的字段,其他字段需要使用方法

    我们也可以忽略掉该特性,将sql_mode中only_full_group_by配置移除即可

  """

‘’分组查询‘’

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('author__pk')).filter(author_num__gt=1).values('title','author_num')
    print(res)

4.示例四:查询各个作者出的书的总价格

    res = modles.Author.objects.annotate(book_sum_price=Sum('book__price')).values('name','book_sum_price')
    print(res)

 

四、F与Q查询【非常重要】

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

    1.设置字段值允许为空        null=True

    2.设置字段默认值               default=1000

    3.在终端中直接给出默认值  1 provide a default value

  '''

    strong_num = models.IntegerField(verbose_name='库存数',null=True)
    sale_num = models.IntegerField(verbose_name='卖出数',default=1000)

'''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('tilte')+'爆款') 针对字符串数据无法直接拼接

这才是正确答案>>>:
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('爆款')))

# 这里F有一个限制,如果你操作的不是数字类型,而是字符串类型,这样的情况需要再次导入一个模块

'''Q查询:可以改变filter括号内多个条件之间的逻辑运算符,还可以将查询条件的字段改为字符串形式'''


res = models.Book.objects.filter(pk=1,publish_id=3)  
print(res)

返回的结果是 QureySet[]

  因为,filter默认只有一个and关系,所以上面filter括号内的两个条件都要满足,如果想要用到‘或’这个方法,就需要用到‘Q’

改变filter括号内多个条件之间的逻辑运算符>>>:

res = models.Book.objects.filter(Q(pk=1),Q(publish_id=3)) 
# 像这样逗号隔开的依旧是and关系

res = models.Book.objects.filter(Q(pk=1)|Q(publish_id=3))
# 管道符分割才是or的关系

res = models.Book.objects.filter(~Q(pk=1)|Q(publish_id=3))
# 波浪号是not关系
print(res.query)

将查询条件的字段改为字符串形式'''>>>:

q_obj = Q()
q_obj.connector = 'or'  # q对象默认的多个条件也是and关系,可以修改为or
q_obj.children.append('pk',1)
q_obj.children.append(('publish_id',3))
res = models.Book.objects.filter(q_obj)
print(res)

 

五、ORM查询优化

 django orm默认都是惰性查询

 当orm的语句在后续的代码中真正需要使用的时候才会执行

   django orm自带limit分页

  减轻数据库端以及服务端压力(肉眼是看不见的,在底层操作)

 '''   ORM查询优化之only与defer   '''

1.only

 ①only的用法

res = models.Book.objects.only('title','price')
for obj in res:
    print(obj.title)  # only后面括号内含有的字段名
    print(obj.price)   # only后面括号内含有的字段名
    print(obj.publish_time)   # only后面括号内没含有的字段名

  ②only的作用

 only会将括号内填写的字段封装成一个个数据对象,对象在点击的时候不会再走数据库查询

  但是对象也可以点击括号内没有的字段,只不过每次都会走数据库查询

2.defer

  defer与only刚好相反

    数据对象点击括号内出现的字段,每次都会走数据库查询

    数据对象点击括号内没有出现的字段,不会走数据库查询

'''  ORM查询优化之select_related与prefetch_related  '''

   ①select_related

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

res = models.Book.objects.select_related('publish')
"""
    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)

 '''   prefetch_related 底层其实是子查询 ,将查询之后的结果也一次性封装到数据对象中,用户在使用的时候是感觉不出来的 '''

 

六、事务相关操作❓

   1.事务:ACID

   2.事务隔离级别: 脏读  幻读  不可重复读  ...

   3.原生SQL:start transaction\rollback\commit\savepoint

  

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

 

七、模型层常见字段

  

AutoField() int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列
CharField() 字符类型,必须提供max_length参数, max_length表示字符长度
IntegerField() 整数类型,范围在 -2147483648 to 2147483647
BigIntegerField() 长整型(有符号的),范围在 -9223372036854775808 ~ 9223372036854775807
DateField() 日期字段,日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例
DateTimeField() 日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例
DecimalField() 10进制小数
EmailField() 字符串类型,Django Admin以及ModelForm中提供验证机制
BooleanField() 传布尔值,将传入的True存为1,传入的False存为0
TextField() 存储大段文本
FileField() 存储文件数据,自动找指定位置存储,字段存具体路径
ForeignKey() 外键类型在ORM中用来表示外键关联关系
OneToOneField() 通常一对一字段用来扩展已有字段
ManyToManyField() "关联管理器"是在一对多或者多对多的关联上下文中使用的管理器。它存在于两种情况:1.外键关系的反向查询,2.多对多关联关系

 ORM还支持自定义字段

class MyharField(models.Field):
    def __init__(slef,max_length,*args,**kwargs):
        self.max_length = max_length
        super().__init__(max_length=max_length,*args,**kwargs)
        
    def db_type(self,connection):
        return 'char(%s)' % self.max_length
info = MyCharField(max_length=32)

  这里要用关键字参数传参

八、orm常见字段参数

参数 描述
max_length CharField 字段类型长度
verboses_name 给字段设置别名
auto_now 配置上auto_now=True,每次更新数据记录的时候会更新该字段
auto_now_add 配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库
null 用于表示某个字段可以为空
default 为该字段设置默认值
max_digits 作用于 DecimalField 字段类型,表示小数总位数
decimal_places 作用于 DecimalField 字段类型,表示小数后的位数
unique=True 如果设置为unique=True 则该字段在此表中必须是唯一的
db_index=True 如果db_index=True 则代表着为此字段设置索引
to 设置要关联的表
to_field 设置要关联的表的字段
related_name 改变正反查询时的名字
on_delete 当删除关联表中的数据时,当前表与其关联的行的行为

  当字段数据的可能性是可以完全列举出来的时候,应该考虑使用该参数

    性别、学历、成绩

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()

to
to_field
related_name
on_delete


    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.手动创建

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")
    优点:第三张表扩展性强
    缺点:无法使用正反向查询以及多对多四个方法
    

   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")
    

 优点:扩展性强并且支持正反向查询

  缺点:无法使用多对多四个方法

posted @ 2022-09-06 19:45  W-Y-N  阅读(76)  评论(0)    收藏  举报