Django框架学习——5—(数据库、在Django中操作数据库、实战案例:图书管理系统、ORM模型介绍)

时间:2020-6-30 作者:admin


1、数据库

MySQL驱动程序安装

我们使用Django来操作MySQL,实际上底层还是通过Python来操作的。因此我们想要用Django来操作MySQL,首先还是需要安装一个驱动程序。在Python3中,驱动程序有多种选择。比如有pymysql以及mysqlclient等。这里我们就使用mysqlclient来操作。mysqlclient安装非常简单。只需要通过pip install mysqlclient即可安装。
常见MySQL驱动介绍:

  1. MySQL-python:也就是MySQLdb。是对C语言操作MySQL数据库的一个简单封装。遵循了Python DB API v2
    但是只支持Python2,目前还不支持Python3。
  2. mysqlclient:是MySQL-python的另外一个分支。支持Python3 并且修复了一些bug。
  3. pymysql:纯Python实现的一个驱动。因为是纯Python编写的,因此执行效率不如MySQL-python。并且也因为是纯Python编写的,因此可以和Python代码无缝衔接。
  4. MySQL Connector/Python:MySQL官方推出的使用纯Python连接MySQL的驱动。因为是纯Python开发的。效率不高。

Django配置连接数据库

在操作数据库之前,首先先要连接数据库。这里我们以配置MySQL为例来讲解。Django连接数据库,不需要单独的创建一个连接对象。只需要在settings.py文件中做好数据库相关的配置就可以了。

DATABASES = {
    'default': {
        # 数据库引擎(是mysql还是oracle等)
        'ENGINE': 'django.db.backends.mysql',
        # 数据库的名字
        'NAME': 'logic',
        # 连接mysql数据库的用户名
        'USER': 'root',
        # 连接mysql数据库的密码
        'PASSWORD': 'root',
        # mysql数据库的主机地址
        'HOST': '127.0.0.1',
        # mysql数据库的端口号
        'PORT': '3306',
    }
}

# 连接Linux服务器MySQL问题:https://blog.csdn.net/qq473179304/article/details/56665364

连接映射数据库:
Django框架学习——5—(数据库、在Django中操作数据库、实战案例:图书管理系统、ORM模型介绍)
Django框架学习——5—(数据库、在Django中操作数据库、实战案例:图书管理系统、ORM模型介绍)

2、在Django中操作数据库

在Django中操作数据库有两种方式。第一种方式就是使用原生sql语句操作,第二种就是使用ORM模型来操作。
在Django中使用原生sql语句操作其实就是使用python db api的接口来操作。如果你的mysql驱动使用的是pymysql,那么你就是使用pymysql来操作的,只不过Django将数据库连接的这一部分封装好了,我们只要在settings.py中配置好了数据库连接信息后直接使用Django封装好的接口就可以操作了

# 使用django封装好的connection对象,会自动读取settings.py中数据库的配置信息
from django.db import connection

# 获取游标对象
cursor = connection.cursor()
# 拿到游标对象后执行sql语句
cursor.execute("select * from book")
# 获取所有的数据
rows = cursor.fetchall()
# 遍历查询到的数据
for row in rows:
    print(row)

以上的execute以及fetchall方法都是Python DB API规范中定义好的。任何使用Python来操作MySQL的驱动程序都应该遵循这个规范。所以不管是使用pymysql或者是mysqlclient或者是mysqldb,他们的接口都是一样的。

Python DB API下规范下cursor对象常用接口

  1. description:如果cursor执行了查询的sql代码。那么读取cursor.description属性的时候,将返回一个列表,这个列表中装的是元组,元组中装的分别是(name,type_code,display_size,internal_size,precision,scale,null_ok),其中name代表的是查找出来的数据的字段名称,其他参数暂时用处不大。
  2. rowcount:代表的是在执行了sql语句后受影响的行数。
  3. close:关闭游标。关闭游标以后就再也不能使用了,否则会抛出异常。
  4. execute(sql[,parameters]):执行某个sql语句。如果在执行sql语句的时候还需要传递参数,那么可以传给parameters参数。
  5. fetchone:在执行了查询操作以后,获取第一条数据。
  6. fetchmany(size):在执行查询操作以后,获取多条数据。具体是多少条要看传的size参数。如果不传size参数,那么默认是获取第一条数据。
  7. fetchall:获取所有满足sql语句的数据。

项目app文件夹/views.py

from django.shortcuts import render
from django.http import HttpResponse
# 两种连接数据库的方式
from django.db import connection
from pymysql import *


def index(request):
    # 第一种连接数据库方式,pymysql连接数据库
    # conn = connect(host='127.0.0.1', port=3306, databases='django_db1', user='root', password='root', charset='utf8')
    # 第二种连接数据库方式,django中的connection连接数据库
    cursor = connection.cursor()                               # 获取游标对象
    cursor.execute("select * from book")                       # 不会把查询结果直接返回
    
    print(cursor.rowcount)                                     # 执行了sql语句后受影响的行数。
    data = cursor.fetchone()                                   # 查询一条数据
    datas = cursor.fetchall()                                  # 查询所有数据
    data1 = cursor.fetchmany(2)                                # 查询多条数据
    print(data)
    
    # return render(request, 'index.html')
    return HttpResponse("首页")

3、实战案例:图书管理系统

需求

完成图书的增删改查,以及前端的页面的展示
项目文件目录如下:
Django框架学习——5—(数据库、在Django中操作数据库、实战案例:图书管理系统、ORM模型介绍)

front/views.py

from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse
# 两种连接数据库的方式
from django.db import connection           # mysqlclient
from pymysql import *


'''
def index(request):
    # 第一种连接数据库方式,pymysql连接数据库
    # conn = connect(host='127.0.0.1', port=3306, databases='django_db1', user='root', password='root', charset='utf8')
    # 第二种连接数据库方式,django中的connection连接数据库
    cursor = connection.cursor()                               # 获取游标对象
    cursor.execute("select * from book")                       # 不会把查询结果直接返回

    print(cursor.rowcount)                                     # 执行了sql语句后受影响的行数。
    data = cursor.fetchone()                                   # 查询一条数据
    datas = cursor.fetchall()                                  # 查询所有数据
    data1 = cursor.fetchmany(2)                                # 查询多条数据
    print(data)

    # return render(request, 'index.html')
    return HttpResponse("首页")
'''


# 抽离出来复用代码次数多的,视图函数才需要request参数
def get_cursor():
    return connection.cursor()


# 首页
def index(request):
    # 连接数据库查询
    #  cursor = connection.cursor()
    cursor = get_cursor()                       # 查询游标,抽离的复用代码
    cursor.execute('select * from book')        # 查询book表,原生sql语句
    books = cursor.fetchall()                   # 查询所有
    print(books)                  # ((1, 'xxxx', 20.0), (2, 'tttt', 20.01), (3, 'zzzz', 30.02), (4, 'yyyy', 18.99))
    context = {
        "books": books,
    }
    return render(request, 'index.html', context=context)


# 添加图书
def add_book(request):
    # 从form表单中获得前端的post请求信息
    if request.method == 'POST':
        # POST请求,保存数据到数据库
        name = request.POST.get('name')
        price = request.POST.get('price')
        
        cursor = get_cursor()                   # 查询游标,抽离的复用代码
        # 执行原生的mysql插入语句,values('name','price')是字符串
        cursor.execute("insert into book(`name`,`price`) values('%s','%s')" % (name, price))
        # 重定向到首页
        return redirect(reverse('index'))
    else:
        # GET请求,显示界面
        return render(request, 'add_book.html')
    
    
# 图书详情页
def book_detail(request, book_id):
    cursor = get_cursor()
    cursor.execute("select * from book where id=%s" % book_id)
    book = cursor.fetchone()
    context = {
        "book": book,
    }
    return render(request, "book_detail.html", context=context)


# 图书删除操作
def book_delete(request, book_id):
    if book_id:
        cursor = get_cursor()
        cursor.execute("delete from book where id= %s" % book_id)
        return redirect(reverse("index"))
    else:
        return render(request, "book_detail.html")

front/urls.py

# -*- encoding: utf-8 -*-
"""
@File    : urls.py
@Time    : 2020/6/27 21:08
@Author  : chen
front/urls.py
"""
from django.urls import path
from . import views


urlpatterns = [
    path("", views.index, name='index'),
    path("add_book/", views.add_book, name='add_book'),
    path("book_detail/<int:book_id>", views.book_detail, name='book_detail'),
    path("book_delete/<int:book_id>", views.book_delete, name='book_delete'),
]

templates/base.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <ul>
        <!--   点击首页跳转至index名称的路由,即:http://127.0.0.1:8000/front/    -->
        <li><a href="{% url 'index' %}">首页</a></li>
        <li><a href="{% url 'add_book' %}">发布图书</a></li>
    </ul>

    {% block content %}

    {% endblock %}

</body>
</html>

templates/index.html文件

{% extends 'base.html' %}
<!-- 模板继承 -->

{% block content %}
     <table>
        <tr>
            <th>序号</th>
            <th>图书</th>
            <th>名字</th>
        </tr>

        {% for book in books %}
            <tr>
                <td>{{ forloop.counter }}</td>
                <td>{{ book.1 }}</td>
                <td>{{ book.2 }}</td>
            </tr>
        {% endfor %}
    </table>
{% endblock %}

templates/add_book.html文件

{% extends 'base.html' %}
<!-- 模板继承 -->

{% block content %}
    <form action="" method="post">
        <!--    自带csrf验证保护,需要添加    -->
        {% csrf_token %}

        <!--   图书表单信息,br标签是换行,注意type和name     -->
        图书名字:<input type="text" name="name"><br>
        图书价格:<input type="text" name="price"><br>
        <input type="submit" value="提交">

    </form>

{% endblock %}

templates/book_detail.html文件

{% extends "base.html" %}

{% block content %}
<!--    自带csrf验证保护,需要添加    -->
        {% csrf_token %}
     <table>
        <tr>
            <th>序号</th>
            <th>图书</th>
            <th>价格</th>
            <th>操作/删除</th>
        </tr>
        <tr>
            <td>{{ book.0 }}</td>
            <td>{{ book.1 }}</td>
            <td>{{ book.2 }}</td>
            <br>
            <td><a href="{% url 'book_delete' book_id=book.0 %}">删除图书</a></td>
        </tr>
    </table>
{% endblock %}

4、ORM模型介绍

随着项目越来越大,采用写原生SQL的方式在代码中会出现大量的SQL语句,那么问题就出现了:

  • 1.SQL语句重复利用率不高,越复杂的SQL语句条件越多,代码越长。会出现很多相近的SQL语句。
  • 2.很多SQL语句是在业务逻辑中拼出来的,如果有数据库需要更改,就要去修改这些逻辑,这会很容易漏掉对某些SQL语句的修改。
  • 3.写SQL时容易忽略web安全问题,给未来造成隐患。SQL注入。

ORM,全称Object Relational Mapping,中文叫做对象关系映射,通过ORM我们可以通过类的方式去操作数据库,而不用再写原生的SQL语句。通过把表映射成类,把行作实例,把字段作为属性,ORM在执行对象操作的时候最终还是会把对应的操作转换为数据库原生语句。

from django.db import models
# 创建一个模型,对应数据库中的一张表
class Book(models.Model):
    id = models.AutoField()
    name = models.CharField(max_length=100)
    author = models.CharField(max_length=100)
    price = models.FloatField()

# 一个模型的对象,对应数据库表中的一条数据
book = Book(name="Python",author='龟叔',price=89)
# save方法,保存
book.save()
# delete方法,删除
book.delete()

使用ORM有许多优点

  • 1.易用性:使用ORM做数据库的开发可以有效的减少重复SQL语句的概率,写出来的模型也更加直观、清晰。
  • 2.性能损耗小:ORM转换成底层数据库操作指令确实会有一些开销。但从实际的情况来看,这种性能损耗很少(不足5%),只要不是对性能有严苛的要求,综合考虑开发效率、代码的阅读性,带来的好处要远远大于性能损耗,而且项目越大作用越明显。
  • 3.设计灵活:可以轻松的写出复杂的查询。
  • 4.可移植性:Django封装了底层的数据库实现,支持多个关系数据库引擎,包括流行的MySQL、PostgreSQL和SQLite。可以非常轻松的切换数据库。
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:87074139@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。