自学python 进击之路 - Django-ROM

480 阅读7分钟

src=http___5b0988e595225.cdn.sohucs.com_images_20190916_32ce26032b124c3cb145a4231627373d.jpeg&refer=http___5b0988e595225.cdn.sohucs.jpg

ORM-查询操作-1

查询简介

  • 数据库的查询需要使用管理器对象进行
  • 通过MyModel.objects 管理器方法调用查询方法

Snipaste_2021-07-19_15-00-33.png

  • all()方法
用法:MyModel.objects.all()
作用:查询MyModel实体中所有数据
等同于 select* from tabel
返回值: QuerySet 容器对象,内部存放MyModel示例
from bookstore.models import Book
books = Book.objescts.all()
for book  in books:
   print('书名', book.title, '出版社 ' , book.pub)
  • 可以在模型类中定义_ str _方法。自定义QuerySet中的输出格式
    • 例如在Book模型下定义如下:
def __str__(self):
     return '%s_$s_%s_%s'%(self.title, self,price, self.pub, self.market_price)
  • 则在django shell中可得到如下显示输出
>>> from bookstore.models import Book
>>> a1 = Book.objects.all()
>>> a1
<QuerySet [<Book: python_清华大学出版社_20.00_25.00>, <Book: Django_清华大学出版社_70.00_75.00>, <Book: JQuery_机械工业 大学出版社_90.00_85.00>, <Book: Linux_机械工业大学出版社_80.00_65.00>, <Book: HTML5_清华大学出版社_90.00_105.00>]>
>>>
  • values('列1', '列2')
用法:MyModel.objects.values(...)
作用:查询部分列的数据并返回
等同于 select1, 列2 from xxx
返回值:QuerySet
  返回查询结果容器, 容器内存字典, 每个字典代表一条数据,格式为:{'列1':值1'列2': 值2}

Snipaste_2021-07-19_16-07-00.png

  • values_list('列1', '列2')
用法:MyModel.objects.values_list(...)
作用:返回元祖形式的查询结果,等同于select1, 列2 from xxx
返回值: QuerySet 容器对象,内部存放‘元祖’
会将查询出来的数据封装到元祖中,再封装到查询集合QuerySet中

Snipaste_2021-07-19_15-56-24.png

  • order_by()
用法:MyModel.objects.order_by('-列''列')
作用:
  与all()方法不同,他会用sql语句的orderby 子距对查询结果进行根据某个字段选择性的进行排序
 说明:
 默认是按照升序排序。降序排序则需要在列前增加’-‘表示

Snipaste_2021-07-19_16-07-00.png

ORM-查询操作-2

条件查询-方法

  • filter(条件)
语法:MyModel.objects.filer(属性1=值1, 属性2=值2)
作用:返回包含此条件的全部的数据集
返回值:
   QuerySet容器对象,内部存放MyModel 实例
说明:
   当多个属性在一起时为“与”关系、 

示例

# 查询书中出版社为“清华大学出版社”的图书
>>> from bookstore.models import Book
>>> a2 = Book.objects.filter(pud='清华大学出版社')
>>> for book in a2:
...     print('书名:', book.title)
...
书名: python
书名: Django
书名: HTML5
  • exclude(条件)
语法:MyModel.objects.get(条件)
作用:返回满足条件只能返回一条数据查询结果多余一条数据则抛出,Model.MultipleObjectsReturned异常
查询结果如果没有数据则抛出Model.DoesNotExst异常

示例

>>> b1 = Book.objects.get(id=1)
>>> b1
<Book: python_清华大学出版社_20.00_25.00>

查询谓词

  • 定义:做更灵活的条件查询时需要使用查询谓词
  • 说明: 每一个查询谓词是一个独立的查询功能
  • __exatc:等值匹配

示例

Author.objects.filter(id__exact=1)
# 等同于select * from author where id  =1
  • __contains:包含指定值
Author.objects.filter(name__contains= 'w')
# 等同于select * from author where name like '%w%'
  • __statswith: 以xxx开始
  • __endswith:以xxx结束
  • __gt:大于指定值
样例:
Author.objects.filter(age__gt=50)
# 等同于select * from author where age > 50
  • __gte:大于等于
  • __lt:小于
  • __lte:小于等于
  • __in:查询数据是否在指定范围内
样例:
Author.objects.filter(country__in=['中国', '日本', '韩国'])
# 等同于select * from author where country in ('中国','日本','韩国')
  • __range: 查找数据是否指定的区间范围内
# 查找年龄在某一区间的所有作者
Author.objects.filter(age__range=(35,50))
# 等同于SELELCT  .... WHERE Author BETWEEN 35 and 50;

ORM-更新操作

更新单个数据

  • 修改单个实体的某些字段值得步骤
通过get()得到要修改的实体对象
  1. 改 - 通过对象.属性的方式修改数据

  2. 保存

   通过对象.save()保存数据

Snipaste_2021-07-19_20-47-53.png

批量更新数据

  • 直接调用QuerySet的update(属性=值) 实现批量修改
  • 示例:
# 将id大于3的所有图书价格为元
books = Book.objects.filter(id__gt = 3)
books.update(price =0)
# 将所有书的零售价定为100元
books = Book.objects.all()
books.update(market_price=100)

Snipaste_2021-07-19_20-58-54.png

ORM-删除操作

单个数据删除

步骤

  • 查找查询结果对应的一个数据对象
  • 调用这个数据对象的delete()方法实现删除
try:
    auth = Author.objects.get(id=1)
    auth.delete()
except:
    print(删除失败)

批量删除

步骤

  • 查找查询结果集中满足条件的全部QuerySet查询集合对象
  • 调用查询集合对象的delete()方法实现删除
# 删除全部作者中,年龄大于65的全部信息
auths = Author.objects.filter(age__get=65)
auths.dalete()

伪删除

  • 通常不会轻易在业务里把数据真正删掉,取而代之的是做伪删除,即在表中添加一个布尔型字段(is_active),默认是true; 执行删除时。 将欲删除数据的is_active字段值为False
  • 注意:用伪删除时, 确保显示数据的地方,均加了is_active=true的过滤查询

练习3 制作‘删除书籍'的页面

  • 点击'查看所有书籍'页面中的‘删除;删除当前书籍(伪删除)
  • 视图函数delete_book
  • 路由http:// 127.0.0.1:8000/bookstore/detele?book_id=xx
  • 注意:相关查询获取数据的地方,要过滤出活跃数据
# 创建视图views.py

def delete_book(request):
    # 通过获取查询字符串 book_id 拿到要删除的book的id
    book_id = request.GET.get('book_id')
    if not book_id:
        return HttpResponse('---请求异常')
    try:
        book = Book.objects.get(id=book_id, is_active=True)
    except Exception as e:
        print('----delete book get error %s' %(e))
        return HttpResponse('---the book id is error')
    # 将其is_active = False
    book.is_active = False
    book.save()
    return HttpResponseRedirect('/bookstore/all_book')
    # 302条跳转至all_book
 
 # 增加字段 models.py
  is_active = models.BooleanField('是否活跃', default=True)
  
  
 #  配置路由
 path('delete_book', views.delete_book)
 
 # all_book.html
 
  <a href="/bookstore/delete_book?book_id={{book.id}}">删除</a>

F对象和Q对象

F对象

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

  • 作用:

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

from django.db.models import F('列名')
  • 示例1 更新Book 示例中所有的零售价涨10元
Book.objects.all().update(market_price=F('market_price')+10)
'UPDATE `bookstore_book` SET`market_price`=(`bookstore_book`.`market_price`+10)'
# 以上做法好于如下代码
books = Book.objects.all()
for book in books:
   book.market_price = book.marget_price+10
   book.save()

Q对象

  • 挡在获取查询结果集 使用复杂的逻辑或|、 逻辑非~ 等待操作时统可以借助于Q对象进行操作
  • 如:想找出定价低于20元或清华大学出版社的全部书,可以用写成
Book.objects.filter(Q(price__lt=20)|Q(pud='清华大学出版社'))
  • Q对象在数据包django.db.models中。需要先导入再使用
  • 作用 :在条件中用来实现除and(&)以外的or(I)或not(~)操作
运算符:
   & 与操作
   |或操作
   ~ 非操作
   语法:
   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(pud_house='清华大学出版社'))
# 查找不是机械工业出版社的书且价格低于50的书
Book.objects.filter(Q(market_price__lt=50)&~Q(pud_house='机械工业出版社'))

Snipaste_2021-07-20_19-43-36.png

聚合查询和原生数据库操作

聚合查询

  • 聚合查询是指对一个数据表中的一个字段的数据进行部分或全部进行统计查询,查bookstore_book数据表中的全部书的平均价格,查询说有书的总个数等,都要使用聚合查询

  • 聚合查询分为

    • 整表聚合
    • 分组整合

聚合查询-整表聚合

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

  • 聚合函数[需要导入]:

    • 导入方法:from django.db.models import *
    • 聚合函数: Sum、Avg、Count、Max、Min
  • 语法:MyModel.objects.aggregate(结果变量名=聚合函数('列'))

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

聚合查询-分组聚合

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

    • 语法:

      • QuerySet.annotate(结果变量名=聚合函数('列'))
    • 返回值:

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

    MyModel.objects.values('列1'列2')

pud_set = Book.objects.values('pud')
print(pud_set)

Snipaste_2021-07-21_13-50-18.png

  • 示例2 通过返回结果的QuerySet.annotate 方法分组聚合得到分组结果 QuerySet.annotate(名=聚合函数('列'))
pud_count_set = pud_set.annotate(myCount=Count('pud'))
print(pud_count_set)

Snipaste_2021-07-21_14-02-20.png

原生数据库操作

  • Django也可以支持直接用sql语句的方式通信数据库
  • 查询:使用Mymodel.objects.raw()进行数据库查询操作查询
  • 语法:MyModel.objects.raw(sql语句,拼接参数
  • 返回值:RawQuerySet集合对象[支持基础操作, 比如循环]
books = models.Book.objects.raw('select  * from bookstore_book')
for book in books:
    print(books)

原生数据库操作 - SQL注入

  • 定义:用户通过数据上传,将恶意的sql语句提交给服务器。从而达到攻击效果
  • 案例1:用户在搜索好友的表单框输入’1or1 = 1'
s1 = Book.objects.raw('select * from bookstore_book where id=%S'%('1or1 = 1'))

原生数据库操作-cursor

1.导入cursor所在的包

from django.db import connection

  1. 创建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 pud_house = 'xxx出版社' where id=10;')
    
with connection.cursor() as cur:
   # 删除 ID 为 1的一条记录
   cur.execute('delete from bookstore_book where id =10')