Django后端框架(七)ORM更新删除|F对象Q对象|聚合查询|原生数据库操作

【单个数据更新】

修改单个实体的某些字段值的步骤:

  1. 查:通过get()得到要修改的实体对象
  2. 改:通过对象.属性的方式来修改数据
  3. 保存:通过对象.save()保存数据

【批量更新数据】

直接调用QuerySet的update(属性=值)方法来实现批量修改。

样例:

# 将id大于3的所有图书价格定为0元

books = Book.objects.filter(id__gt=3)

books.update(price=0)

# 将所有书的零售价定为100元

books = Book.objects.all()

books.update(market_price=100)


<<<练习-表单更新>>>

要求:

点击页面中的“更新”进入更新页面

提供视图函数update_book,url:http://127.0.0.1:8000/bookstore/update_book/<book_id>

更新页面中显示的当前的书籍信息,且能对定价和零售价进行修改

路由(bookstore/urls.py):

from django.urls import path
from . import views

urlpatterns = [
    path('all_book', views.all_book),  # "查看全部书籍"页面
    path('update_book/<int:book_id>', views.update_book)  # "更新书籍"页面
]

视图函数(仅更新函数部分):

def update_book(request, book_id):
    try:
        book = Book.objects.get(id=book_id)
    except Exception as e:
        print('--update book error is %s'%(e))
        return HttpResponse('--The book is not existed')

    if request.method == 'GET':
        return render(request, 'bookstore/update_book.html', locals())
    elif request.method == 'POST':
        price = request.POST['market_price']
        market_price = request.POST['market_price']
        # 修改
        book.price = price
        book.market_price = market_price
        # 保存
        book.save()
        return HttpResponseRedirect('/bookstore/all_book')  # 跳转到‘查看全部书籍’页面

更新页面(update_book.html):

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>更新书籍</title>
</head>
<body>
<form action="/bookstore/update_book/{{ book.id }}" method="post">
    <p>
        title <input type="text" value="{{ book.title }}" disabled="disabled">
    </p>
    <p>
        pub <input type="text" value="{{ book.pub }}" disabled="disabled">
    </p>
    <p>
        price <input type="text" name="price" value="{{ book.price }}">
    </p>
    <p>
        market_price <input type="text" name="market_price" value="{{ book.market_price }}">
    </p>
    <p>
        <input type="submit" value="更新">
    </p>
</body>
</html>

全部书籍页面中点击“更新”进入更新页面:

<a href="/bookstore/update_book/{{ book.id }}">更新</a>

【单个数据删除】

步骤如下:

  1. 查找查询结果对应的一个数据对象
  2. 调用这个数据对象的delete()方法实现删除

样例:

try:
    auth = Author.objects.get(id=1)
    auth.delete()
except:
    print(删除失败)

【批量删除数据】

 步骤:

  1. 查找查询结果集中满足条件的全部QuerySet查询集合对象
  2. 调用查询集合对象的delete()方法实现删除

样例:

# 删除全部作者中,年龄大于65的全部信息
auths = Author.objects.filter(age__gt=65)
auths.delete()

【伪删除】

通常不会轻易在业务里把数据真正删掉,取而代之的是做伪删除,即在表中添加一个布尔型字段(is_active),默认是True;执行删除时,将欲删除数据的is_active字段设置为False。

**注意:使用伪删除时,确保要显示的数据,均加了is_active=True的过滤查询

【F对象】

定义:一个F对象代表数据库中某条记录的字段的信息

作用:

  • 通常是对数据库中的字段值在不获取的情况下进行的操作
  • 用于类属性(字段)之间的比较

语法:

from django.db.models import F  # 导入F对象

F('列名')  # F对象的使用

>样例1:更新Book实例中所有的零售价涨价10元

# 使用F对象

Book.objects.all().update(market_price=F('market_price')+10)

# 不使用F对象

books = Book.objects.all()

for book in books:

        book.market_price = book.market_price + 10

        book.save()

该例中,使用F对象相当于做了+=处理,不使用F对象则需要把目标值取出来再对值进行处理。

当有多人同时进行操作时,由于不使用F对象的是把值取出来再做处理,因此其结果仅显示一次操作的结果,而使用F对象的不会。

>样例2:对数据库中两个字段的值进行比较,列出哪些书的零售价高于定价

from django.db.models import F
from bookstore.models import Book

books = Book.objects.filter(market_price__gt=F('price'))
for book in books:
    print(book.title, '定价', book.price, '现价', book.market_price)

【Q对象】

作用:当在获取查询结果集使用复杂的逻辑或、逻辑与等操作时,可以借助于Q对象进行操作。

运算符:

  • &:与
  • |:或
  • ~:非

语法:

from django.db.models import Q  # 导入

Q(条件1)|Q(条件2)  # 条件1成立或条件2成立

Q(条件1)&Q(条件2)  # 条件1和条件2同时成立

Q(条件1)&~Q(条件2)  # 条件1成立且条件2不成立

样例:

from django.db.models import Q
# 查找清华大学出版社的书或价格低于50元的书
Book.objects.filter(Q(market_price__lt=50) | Q(pub_house='清华大学出版社'))
# 查找不是机械工业出版社的书且价格低于50元的书
Book.objects.filter(Q(market_price__lt=50) & ~Q(pub_house='机械工业出版社'))

【聚合查询】

对一个数据表中的一个字段的数据进行部分或全部进行统计查询。

查bookstore_book数据表中的全部书的平均价格,查询所有书的总数等,都要使用聚合查询。

  • 整表聚合
  • 分组聚合

【整表聚合】

不带分组的聚合查询时指将全部数据进行集中统计查询。

聚合函数有:Sum, Avg, Count, Max, Min

导入:

from django.db.models import 聚合函数名

语法:

MyModel.objects.aggregate(结果变量名=聚合函数('列'))

# 返回结果:结果变量名和值组成的字典,格式为:{'结果变量名':值}

【分组聚合】

分组聚合是指通过计算查询结果中每一个对象所关联的对象集合,得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。

语法:

QuerySet.annotate(结果变量名=聚合函数('列'))

# 返回结果:QuerySet

步骤:

1、通过先用查询结果MyModel.objects.values查找查询要分组聚合的列

2、通过返回结果的QuerySet.annotate方法分组聚合得到分组结果

样例:统计每个出版社各有多少书

【原生数据库操作】

Django也支持直接用SQL语句的方式通信数据库

  • 查询:使用MyModel.objects.raw()进行数据库查询操作
  • 语法:MyMoodel.objects.raw(SQL语句, 拼接参数)
  • 返回值:RawQuerySet(QuerySet可以继续使用方法,即QuerySet.方法(),RawQuerySet不可以,RawQuerySet只支持基础操作,如循环)

【SQL注入】

使用原生SQL语句时,小心SQL注入

*SQL注入:用户通过数据上传,将恶意的SQL语句提交给服务器,从而达到攻击效果。

案例:用户在搜索好友的表单框里输入'1 or 1=1'

s1 = Book.objects.raw('select * from bookstore_book where id=%s'%('1 or 1=1'))

攻击结果:可以查询出所有用户数据

改正如下:

s1 = Book.objects.raw('select * from bookstore_book where id=%s', ['1 or 1=1'])

使用了raw()的第二个参数,拼接参数。拼接参数会将其内容转换成字符串再传进去。

【原生数据库操作-cursor】

完全跨过模型类操作数据库:查询/更新/删除

步骤:

1、导入cursor所在的包:

from django.db import connection

2、用创建cursor类的构造函数创建cursor对象,再使用cursor对象,为保证在出现异常时能释放cursor资源,通常使用with语句进行创建操作:

from django.db import connection

with connection.cursor() as cur:

        cur.execute('执行SQL语句', '拼接参数')

样例:

# 用SQL语句将id为10的书的出版社改为xxx出版社
from django.db import connection
with connection.cursor() as cur:
    cur.execute('update bookstore_book set pub_house="xxx出版社" where id=10;')

# 删除id为10的一条记录
with connection.cursor() as cur:
    cur.execute('delete from bookstore_book where id=10;')

  • 29
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值