这一部分算是一个过渡的部分,内容相比于前三部分来说,会少一些,主要是讲讲数据库的安装以及基本的有关数据库的操作。
1. MySQL驱动程序安装
我们使用Django来操作MySQL,实际上底层还是通过Python来操作的。因此我们想要用Django来操作MySQL,首先还是需要安装一个驱动程序。
在Python3中,驱动程序有多种选择:
- pymysql
纯Python实现的一个驱动。因为是纯Python编写的,因此执行效率不如MySQL-python。并且也因为是纯Python编写的,因此可以和Python代码无缝衔接。 - mysqlclient
是MySQL-python的另外一个分支。支持Python3 并且修复了一些bug。 - MySQL-python
也就是MySQLdb。是对C语言操作MySQL数据库的一个简单封装。遵循了Python DB API v2
但是只支持Python2,目前还不支持Python3。 - MySQL Connector/Python
MySQL官方推出的使用纯Python连接MySQL的驱动。因为是纯Python开发的。效率不高。
这里我们就使用mysqlclient来操作
mysqlclient安装非常简单,只需要通过pip install mysqlclient即可安装:
这里需要注意的是,我们要在虚拟环境中安装:
2. Django配置连接数据库
在操作数据库之前,首先先要连接数据库。这里我们以配置MySQL为例来讲解。
Django连接数据库,不需要单独的创建一个连接对象。只需要在settings.py文件中做好数据库相关的配置就可以了:
这是默认的配置,ENGINE是数据库引擎,我们可以在以下目录找到Django支持的数据库引擎:
因为这里我们使用的是MySQL,所以这里改成:
'ENGINE': 'django.db.backends.mysql'
下面我们需要根据自己的数据库来配置,在这之前,我们打开MySQL,并创建一个数据库
启动phpStudy:
如果是第一次使用,需要配置连接:
测试连接成功即可进入界面:
新建数据库:
因此name的配置如下:
'NAME': 'django_db'
当然还有一些数据库的密码、端口什么的也需要进行配置,配置如下:
# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASES = {
'default': {
# 数据库引擎(是mysql还是oracle等)
'ENGINE': 'django.db.backends.mysql',
# 数据库的名字
'NAME': 'django_db',
# 连接mysql数据库的用户名
'USER': 'root',
# 连接mysql数据库的密码
'PASSWORD': 'root',
# mysql数据库的主机地址
'HOST': '127.0.0.1',
# mysql数据库的端口号
'PORT': '3306',
}
}
配置好后,运行manage.py,如果配置错误,是不会报错的,只有在操作数据库时才会报错
3. 在Django中操作数据库
下面新建一个名为book的app,我们在book里操作数据库:
在项目下的urls.py文件里做映射:
接着在book里新建urls.py并补充映射的代码:
在book\views.py里补充对应得方法:
运行的时候,这里报了一个错:
可以查看这篇文章:
https://blog.csdn.net/linhai1028/article/details/80300241
处理好后便可以运行了:
在Django中操作数据库有两种方式。第一种方式就是使用原生sql语句操作,第二种就是使用ORM模型来操作。
在Django中使用原生sql语句操作其实就是使用python db api的接口来操作。如果你的mysql驱动使用的是pymysql,那么你就是使用pymysql来操作的,只不过Django将数据库连接的这一部分封装好了,我们只要在settings.py中配置好了数据库连接信息后直接使用Django封装好的接口就可以操作了
为了操作数据库,这里我们还需要新建一张数据表:
然后我们手动创建几条数据:
下面我们回到views.py:
from django.shortcuts import render
from django.http import HttpResponse
# 使用django封装好的connection对象,会自动读取settings.py中数据库的配置信息
from django.db import connection
# Create your views here.
def book(request):
# 获取游标对象
cursor = connection.cursor()
# 拿到游标对象后执行sql语句
cursor.execute("select * from book")
# 获取所有的数据
rows = cursor.fetchall()
# 遍历查询到的数据
for row in rows:
print(row)
return HttpResponse("图书首页")
运行一下,首先界面是没有效果的:
但是pycharm里输出了结果:
以上的execute以及fetchall方法都是Python DB API规范中定义好的。任何使用Python来操作MySQL的驱动程序都应该遵循这个规范。所以不管是使用pymysql或者是mysqlclient或者是mysqldb,他们的接口都是一样的。
4. Python DB API下规范下cursor对象常用接口
description
如果cursor执行了查询的sql代码。那么读取cursor.description属性的时候,将返回一个列表,这个列表中装的是元组,元组中装的分别是:
(name,type_code,display_size,internal_size,precision,scale,null_ok)
其中name代表的是查找出来的数据的字段名称,其他参数暂时用处不大。
rowcount
代表的是在执行了sql语句后受影响的行数。
close
关闭游标。关闭游标以后就再也不能使用了,否则会抛出异常。
execute(sql[,parameters])
执行某个sql语句。如果在执行sql语句的时候还需要传递参数,那么可以传给parameters参数。示例代码如下:
cursor.execute("select * from article where id=%s",(1,))
fetchone
在执行了查询操作以后,获取第一条数据。
fetchmany(size)
在执行查询操作以后,获取多条数据。具体是多少条要看传的size参数。如果不传size参数,那么默认是获取第一条数据。
fetchall
获取所有满足sql语句的数据。
5. 简单图书管理系统实例
1- 完成图书首页
像上篇文章那样新建一个templates文件夹,并在里面新建index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图书首页</title>
</head>
<body>
<h2>这是图书首页</h2>
<ul>
<li><a href="/">首页</a></li>
<li><a href="{% url 'book_add' %}">添加图书</a></li>
<li><a href="{% url 'book_del' %}">删除图书</a></li>
</ul>
<table>
<tr>
<th>序号</th>
<th>图书名称</th>
<th>作者</th>
</tr>
{% for item in book %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ item.1 }}</td>
<td>{{ item.2 }}</td>
</tr>
{% endfor %}
</table>
</body>
</html>
首页的功能是显示所有图书:
2- 使用继承
系统中的功能选择是可以复用的,因此我们可以通过继承来减少我们的代码量
这里我们再新建一个base.html作为父类:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% block title %}
{% endblock %}
<ul>
<li><a href="/">首页</a></li>
<li><a href="{% url 'book_add' %}">添加图书</a></li>
<li><a href="{% url 'book_del' %}">删除图书</a></li>
</ul>
{% block content %}
{% endblock %}
</body>
</html>
那么刚刚的index.html可以改成:
{% extends "base.html" %}
{% block title %}
<h3>图书首页</h3>
{% endblock %}
{% block content %}
<table>
<tr>
<th>序号</th>
<th>图书名称</th>
<th>作者</th>
</tr>
{% for item in book %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ item.1 }}</td>
<td>{{ item.2 }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
如果系统需要完成前端的页面的展示,以及图书的增加和删除,那么我们还需要把图书的增加和删除这两个方法补充一下
3- 完善功能
下面我们以增加图书为例,先在book_add.html里完善功能:
{% extends "base.html" %}
{% block title %}
<h3>图书添加页面</h3>
{% endblock %}
{% block content %}
<form action="" method="post">
图书名字:<input type="text" name="book_name"><br>
图书作者:<input type="text" name="book_author"><br>
<input type="submit" value="提交"><br>
</form>
{% endblock %}
我们保存运行一下:
这里直接提交后:
发现报错了,这时我们回到settings.py,把这行注释即可:
另外,为了检验是否能获取到输入的值,我们在视图函数里接收一下:
def book_add(request):
book_name = request.POST.get("book_name")
print(book_name)
return render(request,"book_add.html")
再来试一下 ,这回能成功接收到了:
既然可以接收到返回的值,那么下面我们继续完善一下程序,让返回的内容真正添加到数据表里,并且添加完成后自动跳转到首页查看结果:
from django.shortcuts import render,redirect,reverse
def get_cursor():
return connection.cursor()
def book_add(request):
if request.method == "POST":
book_name = request.POST.get("book_name")
book_author = request.POST.get("book_author")
print(book_name,",",book_author)
cursor = get_cursor()
try:
cursor.execute("insert into book(`title`,`author`) values('%s','%s')"%(book_name,book_author))
except:
return redirect(reverse('index'))
return redirect(reverse('index'))
else:
return render(request,"book_add.html")
效果如下:
数据表内也发生了相应的变化:
增加图书的功能如上所示,删除的功能同理,这里就不再多说了
刚刚这些类似一个目录,点击书名应该可以看到图书的详细信息,下面我们把这个功能完善一下
4- 获取图书详情
要实现点击书名就跳转的功能,就要在书名处加个a标签跳转:
index.html:
{% for item in book %}
<tr>
<td>{{ forloop.counter }}</td>
<td><a href="{% url 'book_detail' book_id=item.0 %}">{{ item.1 }}</a></td>
<td>{{ item.2 }}</td>
</tr>
{% endfor %}
在book\urls.py里添加映射:
path("book_detail/<int:book_id>",views.book_detail,name="book_detail")
book_detail.html显示图书的详细信息:
{% extends "base.html" %}
{% block title %}
<h3>图书详情页面</h3>
{% endblock %}
{% block content %}
<p>序号:{{ book.0 }}</p>
<p>图书名字:{{ book.1 }}</p>
<p>图书作者{{ book.2 }}</p>
{% endblock %}
最后在views.py里补充方法:
def book_detail(request,book_id):
cursor = get_cursor()
cursor.execute("select * FROM book WHERE id=%d"%book_id)
book = cursor.fetchone()
content = {
'book':book
}
return render(request,"book_detail.html",context=content)
效果如下:
点击名为django的图书,显示详情页面:
当然这里其实可以把删除图书的功能加在这里:
views.py:
def book_del(request,book_id):
if book_id:
cursor = get_cursor()
cursor.execute("DELETE FROM book WHERE id=%d"%book_id)
return redirect(reverse('index'))
else:
return HttpResponse("图书不存在!")
在book_detail.html里添加一个删除图书的a标签跳转:
这样一来,一个简易的图书管理系统就完成了!
最后总结一下,看看各个页面:
图书首页:
添加图书页面:
图书详情页面: