Django中的ORM模型(回顾复习)

Django中的ORM模型

  • ORM模型介绍
    • 模型配置
    • ORM字段类型
      • 类型的选项(可选参数)
    • 模型同步
    • 模型的元数据
    • 外键关联关系
    • 复合类型
  • ORM实现CRUD
    • 使用ORM新增数据
      • save()保存数据
      • create()新增数据
      • bulk_create()批量新增数据
      • 外键关联数据的插入
    • 使用ORM简单查询
      • get()查询单条数据
      • latest()/earliest()返回最晚/最早的一条记录
      • get_or_create()若有记录则返回,若无记录则创建后返回
      • get_object_or_404()如果没有则触发404异常
      • first()/last()返回第一条/最后一条记录
      • all()返回所有的记录
    • 使用ORM修改数据
      • save()修改单条数据
      • update()批量修改数据
      • bulk_update()批量修改数据
    • 使用ORM删除数据
  • 深入查询和事务处理
    • QuerySet结果集
    • QuerySet常用方法
      • 条件判断
      • 链式查询
    • 模型管理器(Manager)
    • 调试技巧
    • 查询条件
      • 多个条件查询
    • 查询优化
      • django-debug-toolbar
      • 优化外键关联查询
      • 使用sql查询
    • 分页处理
    • 聚合及统计
      • 实现数据统计
      • 实现聚合查询
    • 数据的一致性
      • F()函数保证多线程操作下数据的一致
      • 当同时操作多个表,怎么保证数据的一致性
        • 在django中使用事务:

ORM模型介绍

模型配置

Django中的ORM模型(回顾复习)_第1张图片
default:默认数据库
ENGINE:数据库引擎
NAME:数据库名称
USER:数据库登陆用户名
PASSWORD:数据库登陆密码
HOST:数据库访问地址
PORT:端口号

Django使用mysql数据库时需安装依赖:pip install mysqlclient

ORM字段类型

Django ORM模型中提供的常用字段:
Django中的ORM模型(回顾复习)_第2张图片
对于CharField,max_length为必选参数
Django中的ORM模型(回顾复习)_第3张图片
Django中的ORM模型(回顾复习)_第4张图片
Django中的ORM模型(回顾复习)_第5张图片
对于DateTimeField
auto_now:更新时间为记录更改的时间
auto_now_add:记录创建的时间

Django中的ORM模型(回顾复习)_第6张图片

类型的选项(可选参数)

每个类型都有可选参数,部分类型有必传参数。
一般情况下,第一个参数不指定名称。

1.(大多数模型类型的第一个参数)verbose_name:表示字段的含义
2.null,blank:是否为Null,空值(空字符串)
3.db.column:数据库表中对应的字段名称
4.default:不填写字段值时的默认值
5.primary_key,unique:主键,唯一索引
6.help_text:帮助文字
7.choices:可供选择的选项(get_xxx_display():展示choices对应的值)

模型同步

1.检查模型是否编写无误
python manage.py check
2.生成同步原语
python manage.py makemigrations
3.执行同步
python manage.py migrate

模型的元数据

元数据:在模型里再写一个类(Meta)
作用:对模型的补充说明

db_table:模型映射的数据库表的名称
ordering:指定数据表的默认排序规则
verbose_name:供编程查看的字段名称
abstract:True,抽象类,不会生成数据库表
proxy:代理模型(代理父模型的功能,并对父模型功能进行扩充)

外键关联关系

  1. 一对一关系: OneToOneField(to,on_delete,parent_link=False,**options)
  2. 一对多关系: ForeignKey(to,on_delete,**options)
  3. 多对多关系: ManyToManyField(to,**options)

参数:
to:关联的模型(必传)

  1. 模型类
  2. 模型类(字符串)
  3. self(外键关联的是自己的情况)

on_delete:删除选项(必传)

  1. CASCADE:关联删除
  2. PROTECT:受保护,不允许被删除
  3. SET_NULL:设置为null,需要添加选项null=True
  4. SET_DEFAULT:设置默认值,需要添加选项default
  5. SET():传参设置值
  6. DO_NOTHING:什么都不做

related_name:是否需要反向引用,反向引用的名称
related_query_name:反向引用的名称

复合类型

Django自带模型(类容模型):ContentType
它会将创建的模块和定义的模型都记录下来

通过外键ForeignKey(ContentType)关联复合模型。
GenericForeignKey关联模型
GenericRelation反向关联

ORM实现CRUD

使用ORM新增数据

Django shell:
1.从终端进入项目目录下,python manage.py shell
2.从pycharm进入[Python Console]

首先需要引入写好的模型
1.save():保存数据
2.create():新增数据
3.bulk_create():批量新增数据

save()保存数据

user_obj = User(username=‘admin’,password=‘123’)
user_obj.save()

create()新增数据

user_obj = User.objects.create(username=‘admin’,password=‘123’)

bulk_create()批量新增数据

user1 = User(username=‘admin’,password=‘123’)
user2 =User(username=‘normal’,password=‘123’)
user3 = …

user_list = [user1,user2,user3,…]

User.objects.bulk_create(user_list)

外键关联数据的插入

user1 = User(username=‘admin’,password=‘123’)
LoginHistory.objects.create(user=user1, *args, **kwargs)
注:需要传入外键关联的对象或是对象id

使用ORM简单查询

  1. get(**kwargs)
  2. latest(*fields)/earliest(*fields)
  3. get_or_create(*args, **kwargs)
  4. get_object_or_404()
  5. first()/last()
  6. all()

get()查询单条数据

user_obj = User.objects.get(pk=1)

latest()/earliest()返回最晚/最早的一条记录

obj = LoginHistory.objects.earliest(‘created_at’)

注意异常的处理:

  • DoesNotExist:查询的记录不存在
  • MultipleObjectsReturned:查询的记录有多条

get_or_create()若有记录则返回,若无记录则创建后返回

object,created = User.objects.get_or_create()
返回一个元组:(对象,是否创建)

get_object_or_404()如果没有则触发404异常

在视图函数中使用。

first()/last()返回第一条/最后一条记录

user_obj = User.objects.last()

如果记录没有会返回None

all()返回所有的记录

user_list = User.objects.all()

使用ORM修改数据

  • save()修改单条数据
  • update(*args,**kwargs)批量修改数据
  • bulk_update(objs,fields,batch_size=None)批量修改数据

save()修改单条数据

user_obj = User.objects.get(pk=1)
user_obj.nickname = ‘admin’
user_obj.save()

update()批量修改数据

方法一:统一修改

user_list = User.objects.all()
user_list.update(status=0)

方法二:循环逐一修改

for user in user_list:
  user.status = 0
  user.save()

bulk_update()批量修改数据

bulk_update(objs,fields,batch_size=None)

objs:需要修改的记录列表
fields:指定需要修改的字段
batch_size:每次提交多少条记录进行修改

使用ORM删除数据

  • delete()物理删除数据

删除单条记录:

user_obj = User.objects.get(pk=1)
user_obj.delete()

删除多条记录:

User.objects.all().delete()

注意外键关联的删除

深入查询和事务处理

QuerySet结果集

  • QuerySet表示从数据库中取出的对象的集合
  • 它可以有零个,一个或多个过滤器(filter)
  • 从模型的Manager那里取得QuerySet
  • QuerySet的筛选结果本身还是QuerySet(可以链式调用)
  • QuerySet是惰性

QuerySet常用方法

条件判断

exists()判断结果集是否存在

User.objecrs.all.exists()

返回布尔值

链式查询

Django中的ORM模型(回顾复习)_第7张图片
Django中的ORM模型(回顾复习)_第8张图片

模型管理器(Manager)

  • Manager是Django的模型进行数据库查询操作的接口
  • 每个模型都拥有至少一个Manager
  • Django为每个模型类添加一个名为objects的默认Manager

Django中的ORM模型(回顾复习)_第9张图片

调试技巧

  • 打印查询执行的SQL语句

print(QuerySet.query)

  • IDE工具的查询调试

查询条件

Django中的ORM模型(回顾复习)_第10张图片
Django中的ORM模型(回顾复习)_第11张图片

User.objects.filter(username__iexact=‘xxx’)

Django中的ORM模型(回顾复习)_第12张图片

User.objects.filter(nickname__isnull=True).count()

Django中的ORM模型(回顾复习)_第13张图片

User.objects.filter(username__icontains=‘xxx’)

Django中的ORM模型(回顾复习)_第14张图片

User.objects.filter(username__in=[‘xxx’,‘xx’])

Django中的ORM模型(回顾复习)_第15张图片

User.objects.filter(username__startswith=‘xxx’)

Django中的ORM模型(回顾复习)_第16张图片

User.objects.filter(updated_at__date=日期对象)

外键关联查询:
UserProfile.objects.filter(user__nickname=‘管理员’)
user:UserProfile与User模型的外键关联

多个条件查询

filter深入使用:

User.objects.filter(nickname__icontains=‘管理员’).filter(status=1)

User.objects.filter(nickname__icontains=‘管理员’, status=1)

&运算符:

user_list =User.objects.filter(nickname__icontains=‘管理员’)&User.objects.filter(status=1)

重点 Q()函数:

  • 实现复杂的查询
  • 支持&(且),|(或),对应sql中的AND和OR

需要先引入

from django.db.models import Q
query1 = Q(nickname__icontains=‘管理员’, status=1)
User.objects.filter(query1)
AND:
query2 = Q(nickname__icontains=‘管理员’) & Q(status=1)
User.objects.filter(query2)
OR:
query3 = Q(username=‘xxx’) | Q(nickname__icontains=‘管理员’)
User.objects.filter(query3 )

查询优化

django-debug-toolbar

1.安装

pip install django-debug-toolbar

2.使用-参考官方文档:

https://django-debug-toolbar.readthedocs.io/en/latest/installation.html

优化外键关联查询

Django中的ORM模型(回顾复习)_第17张图片

使用sql查询

一:使用管理器的raw(sql)函数
返回django.db.models.query.RawQuerySet实例

二:获取数据库连接,游标,直接执行sql

  1. 获取数据库连接:from django.db import connection
  2. 从连接得到游标:cursor = connection.cursor()
  3. 执行sql:cursor.execute(sql)
  4. 得到结果:row = cursor.fetchone()

分页处理

使用分页也是查询优化的一部分

方式一:对查询结果集QuerySet进行分片
返回前n个对象:

User.objects.all()[:n]

返回第11到第20个对象

User.objects.all()[10:20]
[10:20]:切片左闭右开

page = request.GET.get('page', 1)
page = int(page)
page_size = 10
start = (page-1) * page_size
end = page * page_size
user_list = User.objects.all()[start:end]

方式二:使用django.core.paginator进行分页处理√

  1. 取得分页器 p = Paginator(objects,page_size)
    objects:要进行分页的数据
    page_size:每页数据的多少
  2. 取得某一页的对象 page_data = p.get_page(page_num)
    page_num:当前页的页码,如第几页
page = request.GET.get('page', 1)
page = int(page)
user_list = User.objects.all()
p = Paginator(user_list, 15)
page_data = p.get_page(page)
# page_data = p.page(page)
# get_page会处理一些用户输入的异常行为,而 page不会处理

page_data.object_list:这一页里的数据列表
page_data.number:当前的页码
page_data.paginator.num_pages:总共有多少页

分页处理异常:
Django中的ORM模型(回顾复习)_第18张图片
方式三:使用ListView进行分页(基于面向对象的方式)

views.py:

class UserListView(ListView):
# 配置模板
template_name = 'user_list_class.html'
# 配置要分页的对象
model = User
# 每页放多少条数据
paginate_by = 20
# 分页传递的参数(?page=1),默认是page
page_kwarg = 'p'

urls.py:

path('user/list/class', views.UserListView.as_view(),name='...')

user_list_class.html:

page_obj:分页数据,如页码,当前第几页
object_list:当前页的数据列表
Django中的ORM模型(回顾复习)_第19张图片
Django中的ORM模型(回顾复习)_第20张图片

聚合及统计

实现数据统计

使用aggregate整个查询结果集生成统计数据
返回一个结果

Grade.objects.all().aggregate(Avg(‘score’))
{‘score__avg’: xxx}

指定别名
Grade.objects.all().aggregate(avg=Avg(‘score’))
{‘avg’: xxx}

实现聚合查询

使用annotate为查询结果集中的每一项生成统计数据
在列表中使用,返回多个结果

Student.objects.all().annotate(Sum(‘stu_grade__score’))
{‘stu_grade__score__sum’:xxx}

指定别名
Student.objects.all().annotate(total=Sum(‘stu_grade__score’))
{‘total’:xxx}

数据的一致性

多个线程同时对资源进行操作时而造成数据不一致

F()函数保证多线程操作下数据的一致

  • F()函数从数据库操作层面修改数据。
  • UPDATE grade SET 'score' = 800 -> UPDATE grade SET 'score' = 'score' + 1
  • grade_obj.score = F('score') + 1
  • F()函数可避免同时操作时的竞态条件

当同时操作多个表,怎么保证数据的一致性

事务使用场景:

  • 需要对多个ORM模型操作时
  • 对结果要求严格(要么失败,要么成功)
在django中使用事务:

一.自动提交

使用装饰器

@transaction.atomic()
def view(request):
	# 事务内代码
	do_stuff()

过程解析:

  1. 进入到最外层的atomic代码块时会打开一个事务
  2. 进入到内层atomic代码块时会创建一个标记
  3. 退出内部块时(成功)会释放或(失败)回滚至标记处

使用with语法

def view(request):
	with transaction.atomic():
		# 事务内代码
		do_stuff()

二.手动提交和回滚

使用try,except捕捉异常后不会触发事务自动回滚的操作,故需要手动提交和回滚事务。

try:
	a.save()
	b.save()
	# 放弃自动提交事务
	transaction.set_autocommit(False)
	# 提交事务
	transaction.commit()
except Exception as e:
	print(e)
	# 事务回滚
	transaction.rollback()

你可能感兴趣的:(笔记,python)