Python 自动化(十七)ORM操作

ORM-查询操作

查询简介

  • 数据库的查询需要使用管理器对象 objects 进行

  • 通过 自定义模型类.objects 管理器调用查询方法

  • Python 自动化(十七)ORM操作_第1张图片

查询方法

all()方法
概念与理解
  • 用法:自定义模型类.objects.all()
  • 作用:查询自定义模型实体中所有的数据
  • 等同于 select * from table
  • 返回值:QuerySet 容器对象,内部存放 自定义模型类实例
  • Python 自动化(十七)ORM操作_第2张图片
实验:使用 all方法查询数据

实验:使用 values方法查询数据

实验:使用 values_list 方法查询数据

实验:使用 order_by 方法查询数据

解决方案:

实验:使用 filter 方法查询数据

实验:使用 exclude 方法查询数据

  • 打开 Django Shell 环境,导入模型类,使用 all 方法对数据进行查询

  • (testenv) [root@localhost mysite3]# python3 manage.py shell
    >>> from bookstore.models import Book
    >>> a1 = Book.objects.all()
    >>> a1
    , , , , ]>
    >>> for book in a1:
    ...     print(book.title, book.pub)
    ... 
    Python 清华大学出版社
    Django 清华大学出版社
    JQuery 机械工业出版社
    Linux 机械工业出版社
    HTML5 清华大学出版社

    修改 Book类对象的显示内容,修改模型类中的 __str__ 方法

  • # file: bookstore/models.py
    class Book(models.Model):
        title = models.CharField("书名", max_length=50, default="", unique=True)
        pub = models.CharField("出版社", max_length=50, default="")
        price = models.DecimalField("定价", max_digits=7, decimal_places=2, default=0.0)
        market_price = models.DecimalField("零售价", max_digits=7, decimal_places=2, default=0.0)
    
        def __str__(self):  # 重写__str__方法
            return f"{self.title}, {self.pub}, {self.price}, {self.market_price}"
    
        class Meta:
            db_table = "book"

    重新打开 Django Shell 环境,导入模型类,使用 all 方法对数据进行查询

  • (testenv) [root@localhost mysite3]# python3 manage.py shell
    >>> from bookstore.models import Book
    >>> a1 = Book.objects.all()
    >>> a1
    , , , , ]>
    >>> for book in a1:
    ...     print(book)
    ... 
    Python, 清华大学出版社, 20.00, 25.00
    Django, 清华大学出版社, 70.00, 75.00
    JQuery, 机械工业出版社, 90.00, 85.00
    Linux, 机械工业出版社, 80.00, 65.00
    HTML5, 清华大学出版社, 90.00, 105.00
    values(列1, 列2, ……)
    概念与理解
  • 用法:自定义模型类.objects.values(列1, 列2, ……)
  • 作用:查询部分列的数据并返回
  • 等同于 select列1, 列2 from table
  • 返回值:QuerySet,返回查询结果容器,容器内存字典,每个字典代表一条数据
  • 打开 Django Shell 环境,导入模型类,使用 values 方法对数据进行查询

  • (testenv) [root@localhost mysite3]# python3 manage.py shell
    >>> from bookstore.models import Book
    >>> a2 = Book.objects.values("title", "pub")
    >>> a2
    
    >>> for book in a2:
    ...     print(book["title"], book["pub"])
    ... 
    Python 清华大学出版社
    Django 清华大学出版社
    JQuery 机械工业出版社
    Linux 机械工业出版社
    HTML5 清华大学出版社
    values_list(列1,列2, ……)
  • 概念与理解
  • 用法:自定义模型类.objects.values_list(列1, 列2, ……)
  • 作用:返回元组形式的查询结果
  • 等同于:select 列1, 列2 from xxx
  • 返回值:QuerySet容器对象,将查询出来的数据封装到元组中再封装到查询集合QuerySet中
  • 打开 Django Shell 环境,导入模型类,使用 values_list 方法对数据进行查询

  • (testenv) [root@localhost mysite3]# python3 manage.py shell
    >>> from bookstore.models import Book
    >>> a3 = Book.objects.values_list('title', 'pub')
    >>> a3
    
    >>> for book in a3:
    ...     print(book[0], book[1])
    ... 
    Python 清华大学出版社
    Django 清华大学出版社
    JQuery 机械工业出版社
    Linux 机械工业出版社
    HTML5 清华大学出版社
    order_by()
    概念与理解
  • 用法:自定义模型类.objects.order_by(‘-列’, ‘列’)
  • 作用:与 all() 方法不同,它会用 SQL 语句的 ORDER BY 字句对查询结果根据某个字段进行选择性的排序
  • 说明:默认是按照升序排序,降序排序则需要在列前面加上’-’负号表示
  • 打开 Django Shell 环境,导入模型类,使用 order_by 方法对数据进行查询

  • >>> a4 = Book.objects.order_by("price")  # 默认升序排列
    >>> a4
    , , , , ]>
    >>> for book in a4:
    ...     print(book.title, book.price)
    ... 
    Python 20.00
    Django 70.00
    Linux 80.00
    JQuery 90.00
    HTML5 90.00
    >>> a5 = Book.objects.order_by("-price")  # 通过price价格降序排列
    >>> for book in a5:
    ...     print(book.title, book.price)
    ... 
    JQuery 90.00
    HTML5 90.00
    Linux 80.00
    Django 70.00
    Python 20.00
    >>> a6 = Book.objects.values("title").order_by("-price")  # 和其他查询方法连用
    >>> a6
    
    >>> a6.query
    
    >>> str(a6.query)  # 查询执行的 SQL 语句
    'SELECT `book`.`title` FROM `book` ORDER BY `book`.`price` DESC'
    练习:制作查看所有书籍页面

    需求:制作查看所有书籍页面

  • 视图函数: all_book

  • url: http://127.0.0.1:8000/bookstore/all_book

  • Python 自动化(十七)ORM操作_第3张图片

  • 编写视图函数 bookstore -> views.py

  • # file: bookstore/views.py
    from django.shortcuts import render
    from .models import Book
    
    def all_book(request):
        all_book = Book.objects.all()  # 查询所有图书
        return render(request, "bookstore/all_book.html", locals())

    编写指定模板文件 bookstore -> templates -> bookstore -> all_book.html

  • 
    
    
    
        
        图书首页
    
    
    
    {% for book in all_book %}
        
    {% endfor %}
    
    {{ book.id }} {{ book.title }} {{ book.pub }} {{ book.price }} {{ book.market_price }} 更新 删除

    修改主路由文件 mysite3 -> urls.py

  • # file: mysite3/urls.py
    urlpatterns = [
        path('admin/', admin.site.urls),
        ###day03###
        path("test_static", views.test_static),
        path("music/", include("music.urls")),
        path("sport/", include("sport.urls")),
        path("news/", include("news.urls")),
        ###day04###
        path("bookstore/", include("bookstore.urls")),  # 添加主路由配置
    ]

    修改子路由文件 bookstore -> urls.py

  • # file: bookstore/urls.py
    from django.urls import path
    from . import views
    
    urlpatterns = [
        path("all_book", views.all_book),
    ]

    启动 Django 服务,在浏览器测试 http://127.0.0.1:8000/bookstore/all_book,查看模板是否渲染成功

  • Python 自动化(十七)ORM操作_第4张图片

  • 条件查询

    filter(条件)
    概念与理解
  • 用法:自定义 模型类.objects.filter(属性1 = 值1, 属性2 = 值2)
  • 作用:返回包含此条件的全部的数据集
  • 返回值:QuerySet 容器对象,内部存放自定义模型实例
  • 说明:当多个属性放在一起为 ’与’ 的关系
  • 打开 Django Shell 环境,导入模型类,使用 filter 方法对数据进行查询

  • (testenv) [root@localhost mysite3]# python3 manage.py shell
    >>> from bookstore.models import Book
    >>> b1 = Book.objects.filter(pub="中信出版社")  # 空结果集
    >>> b1
    
    >>> b2 = Book.objects.filter(pub="清华大学出版社")
    >>> b2
    , , ]>
    >>> str(b2.query)
    'SELECT `book`.`id`, `book`.`title`, `book`.`pub`, `book`.`price`, `book`.`market_price` FROM `book` WHERE `book`.`pub` = 清华大学出版社'
    >>> b3 = Book.objects.filter(pub="清华大学出版社", price=70)  # 多个条件是and关系
    >>> b3
    ]>
    >>> str(b3.query)  # 查询底层查询SQL语句
    'SELECT `book`.`id`, `book`.`title`, `book`.`pub`, `book`.`price`, `book`.`market_price` FROM `book` WHERE (`book`.`price` = 70 AND `book`.`pub` = 清华大学出版社)'
    exclude(条件)
    概念与理解
  • 用法:自定义模型类.objects.exclude(条件)
  • 作用:返回不包含此条件的全部数据集
  • 返回值:QuerySet容器对象,内部存放自定义模型实例
实验:使用 exclude 方法查询数据
  • 打开 Django Shell 环境,导入模型类,使用 exclude 方法对数据进行查询

    • >>> from bookstore.models import Book
      >>> books = Book.objects.exclude(pub="清华大学出版社", price=70)
      >>> for book in books:
      ...     print(book)
      ... 
      Python, 清华大学出版社, 20.00, 25.00
      JQuery, 机械工业出版社, 90.00, 85.00
      Linux, 机械工业出版社, 80.00, 65.00
      HTML5, 清华大学出版社, 90.00, 105.00

 get(条件)

概念与理解
  • 用法:自定义模型类.objects.get(条件)

  • 作用:返回满足条件的唯一一条数据

  • 说明:该方法只能返回一条数据

    • 查询结果多于一条数据则抛出 Model.MultipleObjectsReturned 异常
    • 查询结果如果没有数据则抛出 Model.DoesNotExists 异常
实验:使用 get 方法查询数据

常用的查询谓词
__exact 等值匹配
__contains 包含某个值
__startswith 以 XXX 开始
__endswith 以 XXX 结束
__gt 大于某个值
__gte 大于等于某个值
__lt 小于某个值
__lte 小于等于某个值
__in 查找数据是否在指定范围内

  • 打开 Django Shell 环境,导入模型类,使用 get 方法对数据进行查询

  • >>> from bookstore.models import Book
    >>> b1 = Book.objects.get(title="Django")  # 拿到单条数据
    >>> b1
    
    >>> b2 = Book.objects.get(title="Django123")  # 数据不存在报错
    bookstore.models.Book.DoesNotExist: Book matching query does not exist.
    >>> books = Book.objects.get(pub="清华大学出版社")  # 返回多条数据报错
    bookstore.models.Book.MultipleObjectsReturned: get() returned more than one Book -- it returned 3!

    思考

    如何做非等值查询,即 where id > 1,尝试:Book.objects.filter(id>1) ?结果报错

  • >>> from bookstore.models import Book
    >>> Book.objects.filter(id>1)  # 报错
    Traceback (most recent call last):
      File "", line 1, in 
    TypeError: '>' not supported between instances of 'builtin_function_or_method' and 'int'

    查询谓词

    理解与概念
  • 定义:做更灵活的条件查询时需要使用查询谓词
  • 说明:每一个查询谓词是一个独立的查询功能
实验:常用查询谓词演示
  • 打开 Django Shell 环境,导入模型类,使用常用的查询谓词对数据进行查询

  • >>> from bookstore.models import Book
    >>> b1 = Book.objects.filter(id__exact=1)  # __exact
    ]>
    >>> b2 = Book.objects.filter(title__contains='o')  # __contains
    >>> b2
    , ]>
    >>> str(b2.query)
    'SELECT `book`.`id`, `book`.`title`, `book`.`pub`, `book`.`price`, `book`.`market_price` FROM `book` WHERE `book`.`title` LIKE BINARY %o%'
    >>> b3 = Book.objects.filter(title__startswith="D")  # __startswith
    >>> b3
    ]>
    >>> str(b3.query)
    'SELECT `book`.`id`, `book`.`title`, `book`.`pub`, `book`.`price`, `book`.`market_price` FROM `book` WHERE `book`.`title` LIKE BINARY D%'
    >>> b4 = Book.objects.filter(price__gte=75)  # __gte
    >>> b4
    , , ]>
    >>> str(b4.query)
    'SELECT `book`.`id`, `book`.`title`, `book`.`pub`, `book`.`price`, `book`.`market_price` FROM `book` WHERE `book`.`price` >= 75'
    >>> b5 = Book.objects.filter(title__in=["Python", "Ansible", "Django"])  # __in
    >>> b5
    , ]>
    >>> str(b5.query)
    'SELECT `book`.`id`, `book`.`title`, `book`.`pub`, `book`.`price`, `book`.`market_price` FROM `book` WHERE `book`.`title` IN (Python, Ansible, Django)'

    ORM-更新操作

    更新单个数据

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

    • 通过 get() 得到要修改的实体对象

    • 通过 对象.属性 的方式修改数据

    保存

    • 通过对象.save()保存数据
  • 批量更新数据

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

    实验:更新数据

  • 打开 Django Shell 环境,导入模型类,测试单值更新以及批量更新操作

    (testenv) [root@localhost mysite3]# python3 manage.py shell
    >>> from bookstore.models import Book
    >>> b1 = Book.objects.get(id=1)
    >>> b1
    
    >>> b1.price = 22
    >>> b1.save()  # 单值修改
    >>> books = Book.objects.filter(pub="清华大学出版社")
    >>> books
    , , ]>
    >>> books.update(price=1)  # 批量修改
    3
    >>> books = Book.objects.filter(pub="清华大学出版社")
    >>> for book in books:
    ...     print(book.price)
    ... 
    1.00
    1.00
    1.00

    练习:制作更新书籍页面

    需求:

  • 点击查看所有书籍页面中的更新按钮进入更新页面
  • 视图函数:update_book
  • url:http://127.0.0.1:8000/bookstore/update_book/
  • 更新页中显示当前书籍信息,且能对定价和零售价进行修改
  • Python 自动化(十七)ORM操作_第5张图片

 

解决方案:

  • 修改指定模板文件 bookstore -> templates -> bookstore -> all_book.html

  • 
    
    
    
        
        图书首页
    
    
    
    {% for book in all_book %}
        
    {% endfor %}
    
    {{ book.id }} {{ book.title }} {{ book.pub }} {{ book.price }} {{ book.market_price }} 更新 删除

    编写视图函数 bookstore -> views.py

  • from django.shortcuts import render
    from django.http.response import HttpResponse, HttpResponseRedirect
    from .models import Book
    
    def all_book(request):
        all_book = Book.objects.all()
        return render(request, "bookstore/all_book.html", locals())
    
    def update_book(request, book_id):
        # bookstore/update_book/1
        try:
            book = Book.objects.get(id=book_id)
        except Exception as e:
            print('--update book error is:', 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['price']
            market_price = request.POST['market_price']
            # 改
            book.price = price
            book.market_price = market_price
            # 保存
            book.save()
            return HttpResponseRedirect('/bookstore/all_book')

    编写指定模板文件 bookstore -> templates -> bookstore -> update_book.html

  • 
    
    
    
        
        更改书籍
    
    
        

    title

    pub

    price

    market_price

    修改子路由文件 bookstore -> urls.py

  • # file: bookstore/urls.py
    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('all_book', views.all_book),
        path('update_book/', views.update_book),
    ]

    启动 Django 服务,在浏览器测试 http://127.0.0.1:8000/bookstore/all_book,测试更新数据功能

  • Python 自动化(十七)ORM操作_第6张图片

 点击更新按钮

Python 自动化(十七)ORM操作_第7张图片

 Python 自动化(十七)ORM操作_第8张图片

 

ORM-删除操作

单个数据删除

步骤
  • 查找查询结果对应的一个数据对象

  • 调用这个数据对象的 delete() 方法实现删除

  • Python 自动化(十七)ORM操作_第9张图片

 

批量删除

步骤
  • 查找查询结果集中满足条件的全部 QuerySet 查询集合对象

  • 调用查询集合对象的 delete() 方法实现删除

 

伪删除

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

练习:删除图书数据(伪删除)

需求:

  • 点击查看所有书籍页面中的删除;删除当前数据(伪删除)

  • 视图函数:delete_book

  • url: http://127.0.0.1:8000/bookstore/delete?book_id=xx

  • 注意:相关查询获取数据的地方,要过滤出活跃数据

  • Python 自动化(十七)ORM操作_第10张图片

  • 解决方案:

  • 在 Book 模型类中添加 is_active 字段,从而实现数据伪删除

  • class Book(models.Model):
        title = models.CharField("书名", max_length=50, default="", unique=True)
        pub = models.CharField("出版社", max_length=50, default="")
        price = models.DecimalField("定价", max_digits=7, decimal_places=2, default=0.0)
        market_price = models.DecimalField("零售价", max_digits=7, decimal_places=2, default=0.0)
        is_active = models.BooleanField("是否活跃", default=True)  # 添加字段

    实现数据迁移、

  • (testenv) [root@localhost mysite3]# python3 manage.py makemigrations
    (testenv) [root@localhost mysite3]# python3 manage.py migrate

    修改指定模板文件 bookstore -> templates -> bookstore -> all_book.html

  • 
    
    
    
        
        图书首页
    
    
    
    {% for book in all_book %}
        
    {% endfor %}
    
    {{ book.id }} {{ book.title }} {{ book.pub }} {{ book.price }} {{ book.market_price }} 更新 删除

    编写视图函数 bookstore -> views.py

  • from django.shortcuts import render
    from django.http.response import HttpResponse, HttpResponseRedirect
    from .models import Book
    
    def all_book(request):
        # all_book = Book.objects.all()
        all_book = Book.objects.filter(is_active=True)  # 修改查询所有图书方式
        return render(request, "bookstore/all_book.html", locals())
    
    def update_book(request, book_id):
        # bookstore/update_book/1
        try:
            book = Book.objects.get(id=book_id, is_active=True)  # 过滤活跃图书
        except Exception as e:
            print('--update book error is:', 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['price']
            market_price = request.POST['market_price']
            # 改
            book.price = price
            book.market_price = market_price
            # 保存
            book.save()
            return HttpResponseRedirect('/bookstore/all_book')
    
    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:', e)
            return HttpResponse('---The book id is error')
        # 将其is_active 改成False
        book.is_active = False
        book.save()
        # 302跳转至all_book
        return HttpResponseRedirect('/bookstore/all_book')

    修改子路由文件 bookstore -> urls.py

  • # file: bookstore/urls.py
    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('all_book', views.all_book),
        path('update_book/', views.update_book),
        path('delete_book', views.delete_book),
    ]

    启动 Django 服务,在浏览器测试 http://127.0.0.1:8000/bookstore/all_book,测试删除数据功能

  • Python 自动化(十七)ORM操作_第11张图片

 Python 自动化(十七)ORM操作_第12张图片

 查询数据库,查看 is_active 状态是否修改

Python 自动化(十七)ORM操作_第13张图片

原生数据库操作

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

  • 查询:自定义模型类.objects.raw()进行查询操作

  • 返回值:RawQuerySet集合对象【只支持基础操作,如循环】

  • 示例:

  • Python 自动化(十七)ORM操作_第14张图片

 

SQL 注入

概念与理解

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

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

  • 案例:用户在登录时的密码框中输入 ‘1 ir 1=1’

  • 攻击结果:不需要密码可进行登录,窃取用户信息

实验:SQL 注入演示

  • 打开 Django Shell 环境,导入模型类,测试SQL注入以及预防操作

  • (testenv) [root@localhost mysite3]# python3 manage.py shell
    >>> from bookstore.models import Book
    >>> s1 = Book.objects.raw("select * from book where id=%s;" % ("1 or 1=1"))
    >>> s1  # SQL注入
    
    >>> for item in s1:
    ...     print(item.title)
    ... 
    Python
    Django
    JQuery
    Linux
    HTML5
    >>> s2 = Book.objects.raw("select * from book where id=%s;", ["1 or 1=1"])
    >>> for item in s2:  # 防止SQL注入
    ...     print(item.title)
    ... 
    Python

你可能感兴趣的:(Python,自动化学习,自动化,运维,linux,python,开发语言,学习)