django3(三) orm数据表操作

目录​​​​​​​

数据表新增

数据修改

数据删除

数据查询

多表查询

执行SQL语句

数据库事务


数据表新增

ORM框架的数据操作API是在QuerySet类里面定义的,然后由开发者自定义的模型对象调用QuerySet类,实现数据操作。

对模型Vocation进行实例化,再对实例化对象的属性进行赋值,从而实现数据表index_vocation的数据插入。对v对象的属性逐一赋值,再由v对象调用save方法进行数据保存。 模型Vocation的外键名为name,数据表index_vocation中变为name_id,v设置外键字段name的时候,外键字段应以数据表的字段名为准。

python manage.py shell        #进入shell模式

from index.models import *
v=Vocation()
v.job='测试工程师'
v.title='系统工程师'
v.payment=0
v.name_id=3
v.save()
v.id        # 数据新增后,获取新增数据的主键id

其他方法

1、

v=Vocation.objects.create(job='测试工程师',title='系统测试',payment=0,name_id=3)
v.id

 2、

d=dict(job='测试工程',title='系统测试',payment=0,name_id=3)
v=Vocation.objects.create(**d)
v.id

3、

v=Vocation(job='测试工程',title='系统测试',payment=0,name_id=3)
v.save()
 v.id

去重判断get_or_create

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

get_or_create根据每个模型字段的值与数据表的数据进行判断。只要有一个字段的值不同除主键外,就会执行True数据插入。如果完全相同,则False不插入。

 update_or_creat判断当前数据在数据表里是否存在,若存在,更新;否则在数据表里新增数据。

找到匹配就修改,,不匹配就插入。 

1、新增

d=dict(job='软件工程师',title='Java开发',payment=8000,name_id=2)
v=Vocation.objects.update_or_create(**d)
v

2、修改

v=Vocation.objects.update_or_create(**d,defaults={'title':'jave'})
v[0].title

 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)

 

数据修改

 update方法

from index.models import *
v=Vocation()
# id=1的payment的值修改为20000
v=Vocation.objects.get(id=1)
v.payment=20000
v.save()
# 列表
Vocation.objects.filter(job='测试工程师').update(job='测试员')
# 字典
d=dict(job='测试员')
# 不查询,默认全表
Vocation.objects.filter(job='测试工程师').update(**d)
# 内置F方法实现数据自增或自减
# F方法还可以在annotate或filter方法里使用
Vocation.objects.update(payment=6666)
from django.db.models import F
v=Vocation.objects.filter(job='测试工程师')
# 将payment字段原有的数据自增加1
v.update(payment=F('payment')+1)

v1=Vocation.objects.create(job='财务',title='出纳',name_id=1)
v2=Vocation.objects.create(job='财务',title='会计',name_id=1)

v1.payment=1000
v2.title='行政'
Vocation.objects.bulk_update([v1,v2],fields=['payment','title'])

数据删除

# 删除全部
Vocation.objects.all().delete()
Vocation.objects.get(id=1).delete()
Vocation.objects.filter(job='测试员').delete()
# 删除的数据会包括与之外键关联的数据
PersonInfo.objects.get(id=3).delete()

数据查询

修改数据之前需要对模型进行查询,查询方式:单表,多表,子查询和联合查询等。

from index.models import *
# 全表查询
v=Vocation.objects.all()
# 查询第一条数据,从0开始
v[0].job
v

# 查询某个字段
# values方法,数据以列表返回,列表元素以字典表示
v=Vocation.objects.values('job')
v[1]['job']

# values_list方法,数据以列表返回,列表元素以元组表示
v=Vocation.objects.values_list('job')[:3]
v

# 使用get方法查询数据
v=Vocation.objects.get(id=2)
v.job

# 使用filter方法查询数据
v=Vocation.objects.filter(id=2)
v[0].job

# SQL的and查询主要在filter里面添加多个查询条件
v=Vocation.objects.filter(job='网站设计',id=2)
v

# filter的查询条件可设为字典格式
d=dict(job='网站设计',id=2)
v=Vocation.objects.filter(**d)

# SQL的or查询,需要引入Q
from django.db.models import Q
v=Vocation.objects.filter(Q(job='网站设计')|Q(id=2))
v

# SQL的不等于查询,在Q查询前面使用~
v=Vocation.objects.filter(~Q(job='网站设计'))
v
# exclude实现不等于查询
v=Vocation.objects.exclude(job='网站设计')
v
# 使用count方法统计查询数据的数据量
v=Vocation.objects.filter(job='网站设计').count()

# 去重查询,distinct方法
v=Vocation.objects.values('job').filter(job='网站设计').distinct()
v

# id降序排序,使用-
v=Vocation.objects.order_by('-id')
v

# 聚合查询,求值、求平均值,annotate(group by)和aggregate方法
from django.db.models import Sum,Count
v=Vocation.objects.values('job').annotate(Sum('id'))
print(v.query)

# aggregate是计算某个字段的值并只返回计算结果
from django.db.models import Count
v=Vocation.objects.aggregate(id_count=Count('id'))
v

# union、intersection和difference
# 每次查询结果的字段必须相同
# 第一次查询结果v1
v1=Vocation.objects.filter(payment_gt=9000)
v1
# 第一次查询结果v2
v2=Vocation.objects.filter(payment_gt=5000)
v2

# 使用SQL的UNION来组合两个或多个查询结果的并集
# 获取两次查询结果的并集
v1.union(v2)
# 使用SQL的INTERSECT来获取两个或多个查询结果的并集
# 获取两次查询结果的交集
v1.intersection(v2)
# 使用SQL的EXCEPT来获取两个或多个查询结果的差
# 以v2为目标数据,去除v1和v2的共同数据
v2.difference(v1)

多表查询

一对一或一对多的表关系是通过外键实现关联的,多表查询分为正向查询和反向查询。

模型Vocation定义的外键字段name关联到模型PersonInfo。

正向查询:如果查询对象的主体是模型Vocation,通过外键字段name去查询模型PersonInfo的关联数据。

反向查询:如果查询对象的主体是模型PersonInfo,查询它与模型Vocation的关联数据。


# 正向查询
# 查询模型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


# 正向查询
# name_name,前面的name是模型Vocation的字段name
# 后面的name是模型PersonInfo的字段name,两者使用双下划线连接
v=Vocation.objects.filter(name_name='Tim').first()
# v.name代表外键name
v.name.hireDate
# 反向查询
# PersonInfo代表外键name的参数related_name
# job代表模型Vocation的字段job
p=PersonInfo.objects.filter(personInfo_job='网站设计').first()
# 通过参数related_name反向获取模型Vocation_set的数据
v=p.personInfo.first()
v.job

select_related 

select_related方法,参数为字符串格式
以模型PersonInfo为查询对象
select_related使用LEFT OUTER JOIN方式查询两个数据表
查询模型PersonInfo的字段name和模型Vocation的字段payment
select_related参数为personInfo,代表外键字段name的参数related_name

p=PersonInfo.objects.select_related('personinfo').values('name','personinfo_payment')
# 查看SQL查询语句
print(p.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

正向查询和反向查询在数据库需要执行2次SQL查询(数据表的数据和外键关联获取另一张数据表的数据信息)

select_related只需要执行一次SQL查询就能实现多表查询。

select_related主要是一对一和一对多关系进行优化,使用join语句优化,减少sql查询次数来优化.

select_related支持3个或3个以上的数据表同时被查询,会增加数据查询时间和内存占用

index/models.py

from django.db import models
# 省份表信息
class Province(models.Model):
    name = models.CharField(max_length=10)

    def __str__(self):
        return str(self.name)

# 城市表信息
class City(models.Model):
    name = models.CharField(max_length=5)
    province = models.ForeignKey(Province, on_delete=models.CASCADE)

    def __str__(self):
        return str(self.name)

# 任务表信息
class Person(models.Model):
    name = models.CharField(max_length=10)
    living = models.ForeignKey(City, on_delete=models.CASCADE)

    def __str__(self):
        return str(self.name)
模型Person通过外键living关联模型City,模型City通过外键province关联模型Province,3个模型形成一种递进关系.
查询Tom居住省份,先通过模型Person和模型city查出Tom所居住的城市,然后通过City和Province查询当前城市所属的省份.
p=Person.objects.select_related('living__province').get(name='Tom')
p.living.province
参数值living__province双下划线
living是模型Person的外键关键字,该字段指向模型City
province是模型City的外键字段,该字段指向模型Province
模型Person的外键字段living指向模型City,再从City的外键字段province指向模型Province
prefetch_related
用python语言分别查询每张表,适合多对多关系的查询。
from django.db import models

# 人员信息
class PersonInfo(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)
    age = models.IntegerField()
    hireDate = models.DateField()

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = '人员信息'

# 节目信息
class Program(models.Model):
    id = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=20)
    performer = models.ManyToManyField(Performer)

    def __str__(self):
        return str(self.name)

​​​​​​​eg:查询节目name为喜洋洋有多少个人参与,从节目表index_program里找出喜洋洋其相关信息,然后通过外键字段performer获取参与的人员信息

# 根据模型Program的某行数据
p=Program.objects.prefetch_related('performer').filter(name='喜洋洋').first()
# 根据外键字段performer获取当前数据的多对多或一对多关系
p.performer.all()

执行SQL语句

extra适合用于ORM难以实现的查询条件,某种程度上可防止SQL注入。

execute能够执行所有SQL语句,但很容易受到SQL注入攻击。

# 查询,where params,select select_params字符串格式化
Vocation.objects.extra(where=["job=%s"],params=['网站设计'])
v=Vocation.objects.extra(select={"seat":"%s"},select_params=['seatInfo'])
print(v.query)
# 连接表,tables多表
v=Vocation.objects.extra(tables=['index_personinfo'])
print(v.query)
# 查询
v=Vocation.objects.raw('select * from index_vocation')
v[0]
# execute执行SQL语句
from django.db import connection
cursor=connection.cursor()
cursor.execute('select * from index_vocation')
# 读取第一行数据
cursor.fetchone()
# 读取所有数据
cursor.fetchall()
# order_by排序略

数据库事务

事务4属性ACID:原子性、一致性、隔离性、持久性。

Django事务定义在transaction.py文件中。

将模型Voction作为事务的操作对象。

index/urls.py
from django.urls import path
from .views import *

urlpatterns = [
    # 定义路由
    path('', index, name='index'),
]
  1. 视图函数使用装饰器使函数支持事务操作
  2. savepoint方法创建事务对象,便于django识别管理
  3. 开始事务操作
  4. 事务操作引入try...except...机制,异常就回滚,使数据操作无效,确保数据一致性
  5. try里,获取请求参数id,存在就根据id值去查询模型数据,对字段自增1;不存在就所有数据自减1并回滚 
from django.shortcuts import render
from .models import *
from django.db import transaction
from django.db.models import F

@transaction.atomic
def index(request):
    # 开启事务保护
    sid = transaction.savepoint()
    try:
        id = request.GET.get('id', '')
        if id:
            v = Vocation.objects.filter(id=id)
            v.update(payment=F('payment') + 1)
            print('Done')
            # 提交事务
            # 如不设置,当程序执行完成后,会自动提交事务
            # transaction.savepoint_commit(sid)
        else:
            # 全表的payment字段自减1
            Vocation.objects.update(payment=F('payment') - 1)
            # 事务回滚,将全表payment字段自减1的操作撤回
            transaction.savepoint_rollback(sid)
    except Exception as e:
        # 事务回滚
        transaction.savepoint_rollback(sid)
    return render(request, 'index.html', locals())

除了使用装饰器,也可以在视图函数中使用with模块实现事务操作。

def index(request):
    pass
    # with 模块里的代码可支持事务操作
    with transaction.atomic():
        pass

本文总结自《Django3 web 应用开发实战-黄永祥》第7章

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值