orm02

ORM-查询操作

查询简介

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

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

查询方法

all()方法
概念与理解
  • 用法:自定义模型类.objects.all()
  • 作用:查询自定义模型实体中所有的数据
  • 等同于 select * from table
  • 返回值:QuerySet 容器对象,内部存放 自定义模型类实例
实验:使用 all方法查询数据
  • 打开 Django Shell 环境,导入模型类,使用 all 方法对数据进行查询

    (testenv) [root@localhost mysite3]# python3 manage.py shell
    >>> from bookstore.models import Book
    >>> a1 = Book.objects.all()
    >>> a1
    <QuerySet [<Book: Book object (1)>, <Book: Book object (2)>, <Book: Book object (3)>, <Book: Book object (4)>, <Book: Book object (5)>]>
    >>> 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
    <QuerySet [<Book: Python, 清华大学出版社, 20.00, 25.00>, <Book: Django, 清华大学出版社, 70.00, 75.00>, <Book: JQuery, 机械工业出版社, 90.00, 85.00>, <Book: , 65.00>, <Book: HTML5, 清华大学出版社, 90.00, 105.00>]>
    >>> 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,返回查询结果容器,容器内存字典,每个字典代表一条数据
实验:使用 values方法查询数据
  • 打开 Django Shell 环境,导入模型类,使用 values 方法对数据进行查询

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

    >>> a4 = Book.objects.order_by("price")  # 默认升序排列
    >>> a4
    <QuerySet [<Book: Python, 清华大学出版社, 20.00, 25.00>, <Book: Django, 清华大学出版社, 70.00, 75.00>, <Book: Linux, 机械工业出版社, 80.00, 65.00>, <Book: J, 85.00>, <Book: HTML5, 清华大学出版社, 90.00, 105.00>]>
    >>> 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
    <QuerySet [{'title': 'JQuery'}, {'title': 'HTML5'}, {'title': 'Linux'}, {'title': 'Django'}, {'title': 'Python'}]>
    >>> a6.query
    <django.db.models.sql.query.Query object at 0x7ffbd8d32b20>
    >>> 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

解决方案:

  • 修改主路由文件 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),
    ]
    
  • 编写视图函数 bookstore -> views.py

    # file: bookstore/views.py
    from django.shortcuts import render
    from .models import Book
    
    
    def all_book(request):
        # return render(request, "bookstore/all_book.html")
        all_book = Book.objects.all()  # 查询所有图书,把数据传递给模板
        return render(request, "bookstore/all_book.html", locals())
    	# locals()相当于传递一个字典 dict = {'all_book': all_book} 给模板
    
  • 编写指定模板文件 bookstore -> templates -> bookstore -> all_book.html

    <!-- file: bookstore/templates/bookstore/all_book.html -->
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>图书首页</title>
    </head>
    <body>
    <table border="1px" cellspacing="0">
    {% for book in all_book %}
        <tr>
            <td>ID</td>
            <td>书名</td>
            <td>出版社</td>
            <td>价格</td>
            <td>市场价</td>
            <td>操作</td>
        </tr>
        <tr>
            <td>{{ book.id }}</td>
            <td>{{ book.title }}</td>
            <td>{{ book.pub }}</td>
            <td>{{ book.price }}</td>
            <td>{{ book.market_price }}</td>
            <td>
                <a href="">更新</a>
                <a href="">删除</a>
            </td>
        </tr>
    {% endfor %}
    </table>
    </body>
    </html>
    
    
  • 启动 Django 服务,在浏览器测试 http://127.0.0.1:8000/bookstore/all_book,查看模板是否渲染成功

    mysites]# python3 manage.py runserver
    

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

练习:添加新图书

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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


# file: bookstore/views.py
from django.shortcuts import render
from django.http.response import HttpResponse, HttpResponseRedirect
from .models import Book
def all_book(request):
    # return render(request, "bookstore/all_book.html")
    all_book = Book.objects.all()  # 查询所有图书,把数据传递给模板
    return render(request, "bookstore/all_book.html", locals())
	# locals()相当于传递一个字典 dict = {'all_book': all_book} 给模板
def add_book(request):
    # 判断是GET还是POST
	# 如果是GET,响应模板过去,如果是POST,执行数据插入
    if request.method == 'GET':
    	return render(request, "bookstore/add_book.html")
    elif request.method == 'POST':
    	pass
    # 获取表单提交的值
    print(request.POST['title_1'])
    # 通过模型类将数据插入到数据库
    Book.objects.create(title=request.POST['title_1'],price=request.POST['price_1'],pub=request.POST['pub_1'],market_price=request.POST['market_price_1' ])
    # 跳转到图书列表路由
    return HttpResponseRedirect('/bookstore/all_book')



<!-- file: bookstore/templates/bookstore/add_book.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>title</title>
</head>
<body>
    <form action="/bookstore/add_book" method="post">
    	书名<input type="text" name="title_1"> <br>
    	出版社<input type="text" name="pub_1"><br>
    	价格<input type="text" name="price_1"><br>
    	市场价<input type="text" name="market_price_1"><br>
    	<input type="submit" value="添加">
    </form>
</body>
</html>



<!-- file: bookstore/templates/bookstore/all_book.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>图书首页</title>
</head>
<body>
<table border="1px" cellspacing="0">
{% for book in all_book %}
    <tr>
        <td>ID</td>
        <td>书名</td>
        <td>出版社</td>
        <td>价格</td>
        <td>市场价</td>
        <td>操作</td>
    </tr>
    <tr>
        <td>{{ book.id }}</td>
        <td>{{ book.title }}</td>
        <td>{{ book.pub }}</td>
        <td>{{ book.price }}</td>
        <td>{{ book.market_price }}</td>
        <td>
            <a href="">更新</a>
            <a href="">删除</a>
        </td>
    </tr>
{% endfor %}
</table>
<a href="/bookstore/add_book">添加图书</a>  <!-- 增加跳转链接 -->
</body>
</html>

条件查询

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

    (testenv) [root@localhost mysite3]# python3 manage.py shell
    >>> from bookstore.models import Book
    >>> b1 = Book.objects.filter(pub="中信出版社")  # 空结果集
    >>> b1
    	<QuerySet []>
    >>> b2 = Book.objects.filter(pub="清华大学出版社")
    >>> b2
    	<QuerySet [<Book: Python, 清华大学出版社, 20.00, 25.00>, <Book: Django, 清华大学出版社, 70.00, 75.00>, <Book: HTML5, 清华大学出版社, 90.00, 105.00>]>
    >>> 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
    	<QuerySet [<Book: Django, 清华大学出版社, 70.00, 75.00>]>
    >>> 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 方法查询数据
  • 打开 Django Shell 环境,导入模型类,使用 get 方法对数据进行查询

    >>> from bookstore.models import Book
    >>> b1 = Book.objects.get(title="Django")  # 拿到单条数据
    >>> b1
    	<Book: Django, 清华大学出版社, 70.00, 75.00>
    >>> 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 "<console>", line 1, in <module>
TypeError: '>' not supported between instances of 'builtin_function_or_method' and 'int'

查询谓词

理解与概念
  • 定义:做更灵活的条件查询时需要使用查询谓词
  • 说明:每一个查询谓词是一个独立的查询功能
常用的查询谓词
查询谓词作用
__exact等值匹配
__contains包含某个值
__startswith以 XXX 开始
__endswith以 XXX 结束
__gt大于某个值
__gte大于等于某个值
__lt小于某个值
__lte小于等于某个值
__in查找数据是否在指定范围内
实验:常用查询谓词演示
  • 打开 Django Shell 环境,导入模型类,使用常用的查询谓词对数据进行查询

    >>> from bookstore.models import Book
    >>> b1 = Book.objects.filter(id__exact=1)  # __exact
    	<QuerySet [<Book: Python, 清华大学出版社, 20.00, 25.00>]>
        
    >>> b2 = Book.objects.filter(title__contains='o')  # __contains
    >>> b2
    	<QuerySet [<Book: Python, 清华大学出版社, 20.00, 25.00>, <Book: Django, 清华大学出版社, 70.00, 75.00>]>
    >>> 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
    	<QuerySet [<Book: Django, 清华大学出版社, 70.00, 75.00>]>
    >>> 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
    	<QuerySet [<Book: JQuery, 机械工业出版社, 90.00, 85.00>, <Book: Linux, 机械工业出版社, 80.00, 65.00>, <Book: HTML5, 清华大学出版社, 90.00, 105.00>]>
    >>> 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
    	<QuerySet [<Book: Python, 清华大学出版社, 20.00, 25.00>, <Book: Django, 清华大学出版社, 70.00, 75.00>]>
    >>> 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
    <Book: Python, 清华大学出版社, 20.00, 25.00>
    >>> b1.price = 22
    >>> b1.save()  # 单值修改
    >>> books = Book.objects.filter(pub="清华大学出版社")
    >>> books
    <QuerySet [<Book: Python, 清华大学出版社, 22.00, 25.00>, <Book: Django, 清华大学出版社, 70.00, 75.00>, <Book: HTML5, 清华大学出版社, 90.00, 105.00>]>
    >>> 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/
  • 更新页中显示当前书籍信息,且能对定价和零售价进行修改

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

解决方案:

  • 修改子路由文件 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('update_book/<int:book_id>', views.update_book),
    ]
    
  • 修改指定模板文件 bookstore -> templates -> bookstore -> all_book.html

    <!-- file: bookstore/templates/bookstore/all_book.html -->
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>图书首页</title>
    </head>
    <body>
    <table border="1px">
    {% for book in all_book %}
        <tr>
            <td>{{ book.id }}</td>
            <td>{{ book.title }}</td>
            <td>{{ book.pub }}</td>
            <td>{{ book.price }}</td>
            <td>{{ book.market_price }}</td>
            <td>
                <!-- <a href="/bookstore/update_book">更新</a> -->
                <a href="/bookstore/update_book/{{ book.id }}">更新</a>
                <a href="">删除</a>
            </td>
        </tr>
    {% endfor %}
    </table>
    </body>
    </html>
    
  • 编写视图函数 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):
    def update_book(request, book_id):
        # bookstore/update_book/300 ——》--The book is not existed
        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')
        
        # 如果请求方法为GET,响应模板update_book.html
        # 如果请求方法为POST,获取提交的值,执行修改
        if request.method == 'GET':
    		# 查询出id对应的图书,然后传给模板(locals()),最终显示
            # locals() ——》 { 'book': book }
            return render(request, 'bookstore/update_book.html', locals())
        elif request.method == 'POST':
            # 获取POST传递的值
            price = request.POST['price']
            market_price = request.POST['market_price']
            # 改
            book.price = price
            book.market_price = market_price
            # 保存
            book.save()
            # return HttpResponse('更新成功')
            # 跳转到图书列表
            return HttpResponseRedirect('/bookstore/all_book')
    
  • 编写指定模板文件 bookstore -> templates -> bookstore -> update_book.html

    <!-- file: bookstore/templates/bookstore/update_book.html -->
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>更改书籍</title>
    </head>
    <body>
    <!-- <form action="/bookstore/update_book" method="post"> -->
    <form action="/bookstore/update_book/{{ book.id }}" method="post">
        <p>
            书名 <input type="text" value="{{ book.title }}" disabled="disabled">
            <!-- value显示的值 disabled="disabled"不可输入 -->
        </p>
        <p>
            出版社 <input type="text" value="{{ book.pub }}" disabled="disabled">
        </p>
        <p>
            价格 <input type="text" name="price" value="{{ book.price }}">
        </p>
        <p>
            市场价 <input type="text" name="market_price" value="{{ book.market_price }}">
        </p>
        <p>
            <input type="submit" value="更新">
        </p>
    </form>
    </body>
    </html>
    
  • 启动 Django 服务,在浏览器测试 http://127.0.0.1:8000/bookstore/all_book,测试更新数据功能

  • 点击更新按钮

ORM-删除操作

单个数据删除

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

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

>>> b1 = Book.objects.get(id=2)
>>> b1
	<Book: 书名: Django,价格: 18.00>
>>> b1.delete()
	(1, {'bookstore. Book': 1})

批量删除

步骤
  • 查找查询结果集中满足条件的全部 QuerySet 查询集合对象
  • 调用查询集合对象的 delete() 方法实现删除
>>> b2 = Book.objects.filter(price__gt=50)
>>> b2
	<QuerySet[<Book:书名:Linux,价格:80.00>,<Book:书名:HTML5,价格:100.00>,<Book:书名:Java,价格:65.00>]>
>>> b2.delete()

伪删除

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

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

需求:

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

  • 视图函数:delete_book

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

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

解决方案:

  • 在 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
    
    查看数据库,可以发现多了字段is_active
    
  • 修改子路由文件 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/<int:book_id>', views.update_book),
        path('delete_book', views.delete_book),
    ]
    
  • 修改指定模板文件 bookstore -> templates -> bookstore -> all_book.html

    <!-- file: bookstore/templates/bookstore/all_book.html -->
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>图书首页</title>
    </head>
    <body>
    <table border="1px">
    {% for book in all_book %}
        <tr>
            <td>{{ book.id }}</td>
            <td>{{ book.title }}</td>
            <td>{{ book.pub }}</td>
            <td>{{ book.price }}</td>
            <td>{{ book.market_price }}</td>
            <td>
                <!-- book.id传递方式一 --> 
                <a href="/bookstore/update_book/{{ book.id }}">更新</a>
                <!-- book.id传递方式二 --> 
                <a href="/bookstore/delete_book?book_id={{ book.id }}">删除</a>
            </td>
        </tr>
    {% endfor %}
    </table>
    </body>
    </html>
    
  • 编写视图函数 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/300 ——》--The book is not existed
        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')
        
        # 如果请求方法为GET,响应模板update_book.html
        # 如果请求方法为POST,获取提交的值,执行修改
        if request.method == 'GET':
    		# 查询出id对应的图书,然后传给模板(locals()),最终显示
            # locals() ——》 { 'book': book }
            return render(request, 'bookstore/update_book.html', locals())
        elif request.method == 'POST':
            # 获取POST传递的值
            price = request.POST['price']
            market_price = request.POST['market_price']
            # 改
            book.price = price
            book.market_price = market_price
            # 保存
            book.save()
            # return HttpResponse('更新成功')
            # 跳转到图书列表
            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('---请求异常,要删除的id不存在')
        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')
    
  • 启动 Django 服务,在浏览器测试 http://127.0.0.1:8000/bookstore/all_book,测试删除数据功能

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

原生数据库操作

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

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

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

  • 示例:

SQL 注入

概念与理解

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

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

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

    
    如果使用原生语句:
    select * from user where username = xxx and password = yyy
    
    用户登陆时密码框输入‘1 or 1=1’
    select * from user where username = zhangsan and password = 1 or 1 = 1
    结果:不需要正确密码也可进行登录
    
  • 攻击结果:不需要密码可进行登录,窃取用户信息

实验:SQL 注入演示

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

    (testenv) [root@localhost mysite3]# python3 manage.py shell
    >>> from bookstore.models import Book
    
    # 当语句过于复杂,而无法使用models时,可以使用raw来执行复杂的sql语句
    
    >>> s1 = Book.objects.raw("select * from book where id=%s;" % ("1 or 1=1"))
    >>> s1  # SQL注入
    <RawQuerySet: select * from book where id=1 or 1=1;>
    >>> for item in s1:
    ...     print(item.title)
    ... 
        Python           # where id=1 or 1=1
        Django
        JQuery
        Linux
        HTML5
    >>> s2 = Book.objects.raw("select * from book where id=%s;", ["1 or 1=1"])
    							# 由于%s只占了一个位,所以只取中括号中的一位
    
    >>> for item in s2:  # 防止SQL注入
    ...     print(item.title)
    ... 
    	Python          # where id=1
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值