django07 orm3

143 阅读5分钟

正反向查询进阶操作

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

聚合查询

  • 聚合函数
    maxminsum,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('pk'))
    

分组查询

默认只能够直接获取分组的字段,其他字段需要使用方法我们也可以忽略掉该特性 将sql_mode中only_full_group_by配置移除即可

  • 1.统计每一本书的作者个数
    # 按照整条数据分组,按照书籍记录分组
    res = models.Book.objects.annotate(author_num=Count('authors__pk')).values('title','author_num')
    # 按照表中的字段分组 annotate之前values括号中指定的字段分组
    res1 = models.Book.objects.values('publish_id').annotate(book_num=Count('pk')).values('publish_id','book_num')
    
  • 2.统计出每个出版社卖的最便宜的书的价格
    res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price')
    
  • 3.统计不止一个作者的图书
    res = models.Book.objects.annotate(count_author=Count('author__pk')).values('publish_id','book_num')
    
  • 4.查询各个作者出的书的总价格
    res = models.Author.objects.annotate(book_sum_price=Sum('book__price')).values('name','book_sum_price')
    

F查询与Q查询

对于表中有数据又要添加新数据的时候,需要指定一些参数
  1.设置字段值允许为空     null=True
  2.设置字段默认值        default=1000
  3.在终端中直接给出默认值  1 provide a default values
  • F查询
    • 查询条件来自表中其他字段,而非自定义字段
使用前需要先导入模块
from django.db.models import F
1.查询库存数大于卖出的书籍
res = models.Book.objects.filter(storage_num__gt=F('sale_num'))
2.将所有书籍的价格上涨1000
res = models.Book.objects.update(price=F('price') + 1000)
3.将所有(特定的)书籍名称加上爆款后缀
* 修改字符串类型的模块时需要额外导入模块
  """
  from django.db.models.functions import Concat
  from django.db.models import Value
  """
res = models.Book.objects.filter(pk=5).update(title=Concat(F('title'), Value('爆款'))))

  • Q查询
    • 执行更复杂的查询(例如OR语句),必须使用q查询。
    • 改变多个条件之间的逻辑运算符,还能将查询条件的字段改为字符串形式
使用前需要先导入模块
from django.db.models import Q
"""
多个条件之间用管道符|是或的关系
取反在Q的前面加波浪号~(not)
* 将查询条件的字段改为字符串形式
    Q产生的对象 = Q()
    Q产生的对象.children.append(('pk', 1)) # 添加条件(字符串,数据值)
"""  

orm查询优化

  • orm默认是惰性查询
    • orm语句在后续代码中真正需要使用的时候才会执行
  • orm自带limit分页
    • 减轻数据库端以及服务端的压力
  • 1.ORM查询优化之defer与only
    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相反
    
  • 2.ORM查询优化之select_related与prefetch_related
    res = models.Book.objects.select_related('authors')
    for obj in res:
        print(obj.publish.name)
    * select_related括号内只能接收外键字段(一对一,一对多)自动将表连接。
    * 得出的数据对象通过句点符点击表中数据的时不会再走数据库查询
    
    res = models.Book.objects.prefetch_related('publish')
    for obj in res:
        print(obj.publish.name)
    * prefetch_related底层是子查询,查询后的结果会一次封装到对象中。用户在使用的时候是感觉不出来的
    

事务操作

  • 事务:ACID
  • 事务隔离级别:脏读,幻读,不可重复读
  • 原生SQL:start transaction\rollback\commit\savepoint
from django.db import transaction
try:
    with transaction.atomic():
        pass  # 多条ORM语句
except Exception as e:
        print(e)

模型层常见手段

```
AutoField()
CharField()
IntegerField()
BigIntegerField()
DateField()
DateTimeField()
DecimalField()
EmailField()
BooleanField()  # 传布尔值存数字01
TextField()     # 存储大段文本
FileField()     # 存储文件数据,自动找指定位置存储,字段存具体路径
ForeignKey()
OneToOneField()
ManyToManyField()
``` 
  • ORM还支持自定义字段
    class MyCharField(models.Field):
      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):
          return 'char(%s)' % self.max_length
    info = MyCharField(max_length=32)
    

ORM常见字段参数

max_length
verboses_name
auto_now
auto_now_add
null
default
max_digits
decimal_places
unique=True
db_index=True
choices
"""
   当字段数据的可能性是可以完全列举出来的时候 应该考虑使用该参数
    	性别
    	学历
    	成绩  
        
	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相似,只不过此时从表中的相关字段不需要设置
    
  • 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")