django学习-数据表操作

一、数据表操作

1. 数据新增

由模型实例化对象调用内置方法实现数据新增,比如单数据新增调用create,查询与新增调用get_or_create,修改与新增调用update_or_create,批量新增调用bulk_create

1.1 create()
# 方法一
# 使用create方法实现数据插入
Vocation.objects.create(job='测试工程师',title='系统测试',
payment=0,name_id=3)

# 方法二
# 同样使用create方法,但数据以字典格式表示
d=dict(job='测试工程师',title='系统测试',payment=0,name_id=3)
Vocation.objects.create(**d)

# 方法三
# 在实例化时直接设置属性值
v=Vocation(job='测试工程师',title='系统测试',payment=0,name_id=3)
v.save()

注意:

执行数据插入时,为了保证数据的有效性,我们需要对数据进行去重判断,确保数据不会重复插入。以往的方案都是对数据表进行查询操作,如果查询的数据不存在,就执行数据插入操作。

1.2 get_or_create()

get_or_create根据每个模型字段的值与数据表的数据进行判断,判断方式如下:

  1. 只要有一个模型字段的值与数据表的数据不相同(除主键之外),就会执行数据插入操作。

  2. 如果每个模型字段的值与数据表的某行数据完全相同,就不执行数据插入,而是返回这行数据的数据对象。

    d=dict(job='测试工程师',title='系统测试',payment=10,name_id=3)
    Vocation.objects.get_or_create(**d)

1.3 update_or_create()

update_or_create方法判断当前数据在数据表里是否存在,若存在,则进行更新操作,否则在数据表里新增数据。

# 第一次是新增数据
d=dict(job='软件工程师',title='Java开发',name_id=2,payment=8000)
v=Vocation.objects.update_or_create(**d)
# 第二次是修改数据
v=Vocation.objects.update_or_create(**d,defaults={'title': 'Java'})
1.4 bulk_create()

如果要对某个模型执行数据批量插入操作,那么可以使用bulk_create方法实现,只需将数据对象以列表或元组的形式传入bulk_create方法即可。

v1=Vocation(job='财务',title='会计',payment=0,name_id=1)
v2=Vocation(job='财务',title='出纳',payment=0,name_id=1)
ojb_list = [v1, v2]
Vocation.objects.bulk_create(ojb_list)
2. 数据修改

数据修改必须执行一次数据查询,再对查询结果进行修改操作,常用方法有:模型实例化、update方法和批量更新bulk_update

2.1 模型实例化
v = Vocation.objects.get(id=1)
v.payment = 20000
v.save()
2.2 update()
# 批量更新一条或多条数据,查询方法使用filter
# filter以列表格式返回,查询结果可能是一条或多条数据
Vocation.objects.filter(job='测试工程师').update(job='测试员')
# 更新数据以字典格式表示
d= dict(job='测试员')
Vocation.objects.filter(job='测试工程师').update(**d)
# 不使用查询方法,默认对全表的数据进行更新
Vocation.objects.update(payment=6666)
# 使用内置F方法实现数据的自增或自减
# F方法还可以在annotate或filter方法里使用
from django.db.models import F
v=Vocation.objects.filter(job='测试工程师')
# 将payment字段原有的数据自增加一
v.update(payment=F('payment')+1)
2.3 bulk_create()
# 新增两行数据
v1=Vocation.objects.create(job='财务',title='会计',name_id=1)
v2=Vocation.objects.create(job='财务',title='出纳',name_id=1)
# 修改字段payment和title的数据
v1.payment=1000
v2.title='行政'
# 批量修改字段payment和title的数据
Vocation.objects.bulk_update([v1,v2],fields=['payment','title'])
3. 数据删除

数据删除必须执行一次数据查询,再对查询结果进行删除操作,若删除的数据设有外键字段,则删除结果由外键的删除模式决定。

数据删除有3种方式:删除数据表的全部数据、删除一行数据和删除多行数据,实现方式如下:

# 删除数据表中的全部数据
Vocation.objects.all().delete()
# 删除一条id为1的数据
Vocation.objects.get(id=1).delete()
# 删除多条数据
Vocation.objects.filter(job='测试员').delete()

外键删除模式说明:

  1. PROTECT模式:如果删除的数据设有外键字段并且关联其他数据表的数据,就提示数据删除失败。
  2. SET_NULL模式:执行数据删除并把其他数据表的外键字段设为Null,外键字段必须将属性Null设为True,否则提示异常。
  3. SET_DEFAULT模式:执行数据删除并把其他数据表的外键字段设为默认值。
  4. SET模式:执行数据删除并把其他数据表的外键字段关联其他数据。
  5. DO_NOTHING模式:不做任何处理,删除结果由数据库的删除模式决定。
  6. CASCADE模式:执行数据删除时会删除所有依赖于这条记录的从表中的相关记录,更新时也会更新所有从表中的记录。
4. 数据查询

数据查询分为单表查询和多表查询,Django提供多种不同查询的API方法,以满足开发需求。

4.1 单表查询
# SQL:Select * from index_vocation,数据以列表返回
v = Vocation.objects.all()
# 查询第一条数据,序列从0开始
v[0].job
# 查询前3条数据
# SQL:Select * from index_vocation LIMIT 3
# SQL语句的LIMIT方法,在Django中使用列表截取即可
v = Vocation.objects.all()[:3]
# 查询某个字段
# SQL:Select job from index_vocation
# values方法,数据以列表返回,列表元素以字典表示
v = Vocation.objects.values('job')
v[1]['job']
# values_list方法,数据以列表返回,列表元素以元组表示
v = Vocation.objects.values_list('job')[:3]
# 使用get方法查询数据
# SQL:Select*from index_vocation where id=2
v = Vocation.objects.get(id=2)
# 使用filter方法查询数据,注意区分get和filter的差异
v = Vocation.objects.filter(id=2)
v[0].job
# SQL的and查询主要在filter里面添加多个查询条件
v = Vocation.objects.filter(job='网站设计', id=3)
#filter的查询条件可设为字典格式
d=dict(job='网站设计', id=3)
v = Vocation.objects.filter(**d)
# SQL的or查询,需要引入Q,编写格式:Q(field=value)|Q(field=value)
#多个Q之间使用"|"隔开即可
# SQL:Select * from index_vocation where job='网站设计' or id=9
from django.db.models import Q
v = Vocation.objects.filter(Q(job='网站设计')|Q(id=4))
# SQL的不等于查询,在Q查询前面使用"~"即可
# SQL语句:SELECT * FROM index_vocation WHERE NOT (job='网站设计')
v = Vocation.objects.filter(~Q(job='网站设计'))
#还可以使用exclude实现不等于查询
v = Vocation.objects.exclude(job='网站设计')
# 使用count方法统计查询数据的数据量
v = Vocation.objects.filter(job='网站设计').count()
# 去重查询,distinct方法无须设置参数,去重方式根据values设置的字段执行
# SQL:Select DISTINCT job from index_vocation where job = '网站设计'
v = Vocation.objects.values('job').filter(job='网站设计').distinct()
# 根据字段id降序排列,降序只要在order_by里面的字段前面加"-"即可
# order_by可设置多字段排列,如Vocation.objects.order_by('-id', 'job')
v = Vocation.objects.order_by('-id')
# 聚合查询,实现对数据值求和、求平均值等。由annotate和aggregate方法实现
# annotate类似于SQL里面的GROUP BY方法
#如果不设置values,默认对主键进行GROUP BY分组
# SQL:Select job,SUM(id) AS 'id__sum' from index_vocation GROUP BY job
from django.db.models import Sum, Count
v = Vocation.objects.values('job').annotate(Sum('id'))
# aggregate是计算某个字段的值并只返回计算结果
# SQL:Select COUNT(id) AS 'id_count' from index_vocation
from django.db.models import Count
v = Vocation.objects.aggregate(id_count=Count('id'))
# union、intersection和difference语法
# 每次查询结果的字段必须相同
# 第一次查询结果v1
v1 = Vocation.objects.filter(payment__gt=9000)
# 第二次查询结果v2
v2 = Vocation.objects.filter(payment__gt=5000)
# 使用SQL的UNION来组合两个或多个查询结果的并集
# 获取两次查询结果的并集
v1.union(v2)
# 使用SQL的INTERSECT来获取两个或多个查询结果的交集
# 获取两次查询结果的交集
v1.intersection(v2)
# 使用SQL的EXCEPT来获取两个或多个查询结果的差
# 以v2为目标数据,去除v1和v2的共同数据
v2.difference(v1)

上述的查询条件filterget是使用等值的方法来匹配结果。若想使用大于、不等于或模糊查询的匹配方法,则可在查询条件filterget里使用下面所示的匹配符实现。

  • 精确匹配:Author.objects.filter(name__exact='John Doe')
  • 模糊匹配:Author.objects.filter(name__iexact='john doe')
  • 不等于:Author.objects.filter(name__ne='John Doe')
  • 包含:Author.objects.filter(name__contains='John')
  • 不区分大小写的包含:Author.objects.filter(name__icontains='john')
  • 正则表达式匹配:Author.objects.filter(name__regex=r'^[A-Za-z]')

注意:

  • 查询条件get:查询字段必须是主键或者唯一约束的字段,并且查询的数据必须存在,如果查询的字段有重复值或者查询的数据不存在,程序就会抛出异常信息。
  • 查询条件filter:查询字段没有限制,只要该字段是数据表的某一字段即可。查询结果以列表形式返回,如果查询结果为空(查询的数据在数据表中找不到),就返回空列表。
4.2 多表查询

在日常的开发中,常常需要对多张数据表同时进行数据查询。多表查询需要在数据表之间建立表关系才能够实现。一对多或一对一的表关系是通过外键实现关联的,而多表查询分为正向查询反向查询

# 正向查询
# 查询模型Vocation某行数据对象v
v = Vocation.objects.filter(id=1).first()
# v.name代表外键name
# 通过外键name去查询模型PersonInfo所对应的数据
v.name.hireDate
# 反向查询
# 查询模型PersonInfo某行数据对象p
p = PersonInfo.objects.filter(id=2).first()
# 方法一
# vocation_set的返回值为queryset对象,即查询结果
# vocation_set的vocation为模型Vocation的名称小写
# 模型Vocation的外键字段name不能设置参数related_name
# 若设置参数related_name,则无法使用vocation_set
v = p.vocation_set.first()
v.job
# 方法二
# 由模型Vocation的外键字段name的参数related_name实现
# 外键字段name必须设置参数related_name才有效,否则无法查询
# 将外键字段name的参数related_name设为personinfo
v = p.personinfo.first()
v.job

为了减少查询次数,提高查询效率,我们可以使用select_relatedprefetch_related方法实现,该方法只需执行一次SQL查询就能实现多表查询。

select_related主要针对一对一和一对多关系进行优化,它是使用SQLJOIN语句进行优化的,通过减少SQL查询的次数来进行优化和提高性能,其使用方法如下:

# select_related方法,参数为字符串格式
# 以模型PersonInfo为查询对象
# select_related使用LEFT OUTER JOIN方式查询两个数据表
# 查询模型PersonInfo的字段name和模型Vocation的字段payment
# select_related参数为personinfo,代表外键字段name的参数related_name
# 若要得到其他数据表的关联数据,则可用双下画线"__"连接字段名
# 双下画线"__"连接字段名必须是外键字段名或外键字段参数related_name
p=PersonInfo.objects.select_related('personinfo').
values('name','personinfo__payment')
# 查看SQL查询语句
print(p.query)
# 以模型Vocation为查询对象
# select_related使用INNER JOIN方式查询两个数据表
# select_related的参数为name,代表外键字段name
v=Vocation.objects.select_related('name').values('name','name__age')
# 查看SQL查询语句
print(v.query)
# 获取两个模型的数据,以模型Vocation的payment大于8000为查询条件
v=Vocation.objects.select_related('name').
filter(payment__gt=8000)
# 查看SQL查询语句
print(v.query)
# 获取查询结果集的首个元素的字段age的数据
# 通过外键字段name定位模型PersonInfo的字段age
v[0].name.age
6. 执行SQL语句

执行SQL语句有3种方法实现:extrarawexecute,其中extraraw只能实现数据查询,具有一定的局限性;而execute无须经过ORM框架处理,能够执行所有SQL语句,但很容易受到SQL注入攻击。

  • extra:结果集修改器,一种提供额外查询参数的机制。
    extra适合用于ORM难以实现的查询条件,将查询条件使用原生SQL语法实现,此方法需要依靠模型对象,在某程度上可防止SQL注入

    查询字段job等于'网站设计'的数据

    params为where的%s提供数值

    Vocation.objects.extra(where=["job=%s"],params=['网站设计'])
    <QuerySet [<Vocation: 3>]>

    新增查询字段seat,select_params为select的%s提供数值

    =Vocation.objects.extra(select={"seat":"%s"},
    select_params=['seatInfo'])
    print(v.query)

    连接数据表index_personinfo

    v=Vocation.objects.extra(tables=['index_personinfo'])
    print(v.query)

  • raw:执行原始SQL并返回模型实例对象。
    raw的语法和extra所实现的功能是相同的,只能实现数据查询操作,并且也要依靠模型对象,但从使用角度来说,raw更为直观易懂。

    v = Vocation.objects.raw('select * from index_vocation')
    v[0]
    <Vocation: 1>

  • execute:直接执行自定义SQL
    execute的语法,它执行SQL语句无须经过DjangoORM框架。我们知道Django连接数据库需要借助第三方模块实现连接过程,如MySQLmysqlclient模块和SQLitesqlite3模块等,这些模块连接数据库之后,可通过游标的方式来执行SQL语句,而execute就是使用这种方式执行SQL语句

    from django.db import connection
    cursor=connection.cursor()

    执行SQL语句

    cursor.execute('select * from index_vocation')

    读取第一行数据

    cursor.fetchone()

    读取所有数据

    cursor.fetchall()

execute能够执行所有的SQL语句,但很容易受到SQL注入攻击,一般情况下不建议使用这种方式实现数据操作。尽管如此,它能补全ORM框架所缺失的功能,如执行数据库的存储过程。

7. 数据库事务

数据库事务是指作为单个逻辑执行的一系列操作,这些操作具有原子性,即这些操作要么完全执行,要么完全不执行,常用于银行转账和火车票抢购等。

事务是指作为单个逻辑执行的一系列操作,这些操作具有原子性,即这些操作要么完全执行,要么完全不执行。事务处理可以确保事务性单元内的所有操作都成功完成,否则不会执行数据操作。

事务应该具有4个属性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability),这4个属性通常称为ACID特性。

Django中通过使用 atomic() 装饰器或 transaction.atomic() 上下文管理器来包装需要事务处理的代码块。

  1. 使用 atomic() 装饰器:

    from django.db import transaction

    @transaction.atomic
    def view_func(request):
    # 在此函数内的数据库操作会被自动包装在事务中
    obj1 = MyModel.objects.create(field1='value1', field2='value2')
    obj2 = AnotherModel.objects.create(field='value')
    # 如果任何数据库操作失败,事务会回滚;否则会提交

  2. 使用 transaction.atomic() 上下文管理器:

    from django.db import transaction

    def view_func(request):
    with transaction.atomic():
    # 在此块内的数据库操作会被包装在事务中
    obj1 = MyModel.objects.create(field1='value1', field2='value2')
    obj2 = AnotherModel.objects.create(field='value')
    # 如果任何数据库操作失败,事务会回滚;否则会提交

相关推荐
云和数据.ChenGuang1 小时前
Django 应用安装脚本 – 如何将应用添加到 INSTALLED_APPS 设置中 原创
数据库·django·sqlite
woshilys2 小时前
sql server 查询对象的修改时间
运维·数据库·sqlserver
Hacker_LaoYi2 小时前
SQL注入的那些面试题总结
数据库·sql
建投数据3 小时前
建投数据与腾讯云数据库TDSQL完成产品兼容性互认证
数据库·腾讯云
Hacker_LaoYi4 小时前
【渗透技术总结】SQL手工注入总结
数据库·sql
岁月变迁呀4 小时前
Redis梳理
数据库·redis·缓存
独行soc4 小时前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍06-基于子查询的SQL注入(Subquery-Based SQL Injection)
数据库·sql·安全·web安全·漏洞挖掘·hw
你的微笑,乱了夏天4 小时前
linux centos 7 安装 mongodb7
数据库·mongodb
工业甲酰苯胺5 小时前
分布式系统架构:服务容错
数据库·架构
南宫生5 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论