ORM(下)

内容概要

  • Q查询进阶操作
  • ORM查询优化
  • ORM事务操作
  • ORM常用字段类型
  • ORM常用字段参数
  • ORM三种创建多对多方式

Q查询进阶操作

"""
Q查询的进阶操作
"""
from django.db.models import Q
# 先产生Q对象
q_obj = Q()
# 确认条件之间的连接关系
q_obj.connector = 'or'  # 以 or连接
# 添加条件  pk=1
q_obj.children.append(('pk', 1))
# 在添加 一个 条件 name= '西游记'
q_obj.children.append(('name', '西游记'))
# 现在相当于 pk=1 or name='西游记'
res = models.Book.objects.filter(q_obj)
res1 = models.Book.objects.filter(Q(pk=1) | Q(name='西游记'))
print(res)
print(res1)

ORM查询优化

  1. ORM查询默认都是惰性查询

    就是如果你这行代码后续没有用到 那么我就不会执行

  2. ORM查询自带分页

  3. only

    """数据对象 + 含有指定字段对应的数据"""
    

    一条SQL

    还是一条SQL

    但是在点一个 only括号外的数据的时候

        res = models.Book.objects.only('name', 'price')
        for obj in res:
            print(obj.register_time)
    

    每一次循环都会产生一条SQL语句

    总结:如果是only括号内的字段不走SQL,括号外的走SQL

  4. defer

    res = models.Book.objects.defer('name', 'price')
    for obj in res:
        print(obj.name)
    

    res = models.Book.objects.defer('name', 'price')
    for obj in res:
        print(obj.register_time)
    

    总结:defer在查询括号内的字段的时候做走SQL,括号外的不走SQL

  5. select_related

    res = models.Book.objects.select_related('publish')
    print(res)
    

  6. prefetch_related

    res = models.Book.objects.prefetch_related('publish')
    print(res)
    

总结:select_related是连表操作,perfetch_related是子查询

ORM事务操作

  1. 事务的四大特性(ACID)

    原子性、一致性、隔离性、持久性

  2. 相关SQL关键字

    """
    start transaction; 启动事务
    rollback; 回滚
    commint; 确认 直接刷进内存了
    savepoint;   # 保存点
    """
    
  3. 相关重要概念

    脏读、幻读、不可重复读、MVCC多版本控制....
    
  4. django orm提供了至少三种开启事务的方式

    全局有效

    方式一:配置文件数据库添加相关键值对 全局有效

    "ATOMIC_REQUESTS": True  每次请求所涉及到的ORM操作属于同一个事物
    

    然后再视图函数里面写ORM的操作,如果遇到报错则回滚,返回的不是一个HttpResponse对象的报错不算

    def index_func(request):
        models.Book.objects.create(name='石头记', price='19.9', publish_id=1)
        paa
        return HttpResponse('嘿嘿')
    
    

    执行之前

    执行后

    因为在执行的过程中报错了,所以事务回滚到执行前了所以没有添加进去。

    def index_func(request):
        models.Book.objects.create(name='石头记', price='19.9', publish_id=1)
        return HttpResponse('嘿嘿')
    

    这样就添加进去,虽然事务回滚了,但是主键记录了,它是添加过数据的。

    def index_func(request):
        models.Book.objects.create(name='射雕英雄传', price='19.9', publish_id=1)
        return 111
    

    返回的不是一个HttpResponse对象 的报错不影响事务,

    也是添加成功的

    • 方式二:装饰器 局部有效

      from django.db import transaction
      @transaction.atomic
      def index():pass	
      
    • 方式三:with上下文管理 局部有效

      from django.db import transaction
      def reg():
          with transaction.atomic():
              pass
      

ORM常用字段

  • AutoField

    int自增列,必须要填入参数primary_key=True。如果model中没有自增列,则会自动创建一个列名为id的列

  • IntegerField

    一个整数类型,范围在-2147483648 to 2147483647

    (一般不用它来存手机号(位数也不够),直接用字符串存)

  • CharField

    字符串类型,必须提供max_length参数,max_length表示字符长度。

    这里需要直到的是Django中的CharField对应的MySQL数据库中的varchar类型,没有设置对应char类型的字段,但是Django允许我们自定义新的字段

    自定义字段写法

    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
    
    

    应用

    class UserInfo(models.Model):
        name = MyCharField(max_length=32)
        phone = models.CharField(max_length=32)
    

  • DateField

    日期字段,日期格式YYYY-MMM-DD,相当于Python中的datetime.date()实例。

  • DateTimeField

    日期时间字段,相当于Python的datetime.datetime()实例

  • BigIntegerField MySQL的bigint

  • SmallIntegerField MySQL的samllint

  • BooleanField

    传布尔值自动存0或1

  • TextField

    存储大段文本

  • EmailField

    存储邮箱格式数据

  • FileField

    传文件对象 自动保存到提前配置好的路径下并存储该路径信息

ORM常用字段参数

primary_key     主键
verbose_name    注释
max_length      字段长度
max_digits      数值的总长度
decimal_places   小数点后面的位数
auto_now       每次操作数据自动更新时间
auto_now_add    首次创建数据的时间
null          允许字段为空
default        字段默认值
unique         唯一值
db_index        给字段添加索引
choices         当某个字段的可能性能够完全列举出来出来的情况下使用
比如:性别、学历、工作状态...

实操

class UserInfo(models.Model):
    name = MyCharField(max_length=32)
    phone = models.CharField(max_length=32)
    # 列举好对应关系
    gender_choice = (
        (1, '男'),
        (2, '女'),
        (3, '其他')
    )
    gender = models.IntegerField(choices=gender_choice, verbose_name='性别', default=1)

取出来

    # res = models.UserInfo.objects.create(name='jason', phone=140, gender=1)
    res = models.UserInfo.objects.filter(name='jason').first()
    print(res.gender)
    print(res.get_gender_display())

to             关联表
to_field         关联字段(不写默认关联数据主键)
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. 全自动创建

    class Book(models.Model):
        title = models.CharField(max_length=32, verbose_name='书名')
        authors = models.ManyToManyField(to='Author')
    
    class Author(models.Model):
        name = models.CharField(max_length=32, verbose_name='姓名')
    

    优势:自动创建第三张表, 并且提供了add、remove、set、clear以及正反向概念

    劣势第三张表无法创建更多的字段 扩展性较差

  2. 全手动

    class Book(models.Model):
        title = models.CharField(max_length=32, verbose_name='书名')
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32, verbose_name='姓名')
    
    
    class Book2Author(models.Field):
        book = models.ForeignKey(to=Book, on_delete=models.CASCADE)
        author = models.ForeignKey(to=Author, on_delete=models.CASCADE)
        others = models.CharField(max_length=32, verbose_name='其他')
        join_time = models.DateField(auto_now_add=True, verbose_name='绑定时间')
    

    优势:第三张表完全由自己创建,扩展性强

    劣势:编写繁琐 并且不在支持add、remove、set、clear以及正方向概念

  3. 半自动

    class Book1(models.Model):
        title = models.CharField(max_length=32)
        authors = models.ManyToManyField(to='Author1',
                                         through='Book1ToAuthor1',
                                         through_fields=('book', 'author'))  # 在哪个表就先填那个字段
    
    
    class Author1(models.Model):
        name = models.CharField(max_length=32)
    
    
    class Book1ToAuthor1(models.Model):
        book = models.ForeignKey(to=Book1, on_delete=models.CASCADE)
        author = models.ForeignKey(to=Author1, on_delete=models.CASCADE)
        join_time = models.DateField(auto_now_add=True)
    

    优势:第三张表完全由自己创建 扩展性强 正反向概念依然可见

    劣势:编写繁琐 不在支持 add、set、remove、clear

posted @ 2022-12-19 21:25  可否  阅读(16)  评论(0编辑  收藏  举报