Django数据库操作与图书管理系统
Django连接数据库
安装MySQL驱动
•当你要使用Django框架来操作MySQL时,底层还是通过Python操作实现的,因此要想用Django框架来操作MySQL时,首先必须要安装数据库驱动程序
•常见MySQL驱动:
•MySQLdb
是对C语言操作MySQL数据库的简单封装,遵循了Python DB API v2
,但是只支持Python2,目前还不支持Python3
mysqlclient
•是MySQL-python
的另外一个分支,支持Python3并且修复了一些bug
pymysql
•纯Python实现的一个驱动,因为是纯Python编写的,因此执行效率不如MySQL-python,但是可以和Python代码无缝衔接
mysql-connector
•MySQL官方推出的使用纯Python连接MySQL的驱动,同样效率不高
•这里我们选择mysqlclient
驱动,直接使用命令pip install mysqlclient
即可安装,如安装出错可能是以下情况造成:
•(1)使用国内网安装,下载速度过慢导致安装失败
解决方案:换源安装
驱动,参考这篇文章pip换源安装python各种库(终极详细版)即可解决
•(1)pip版本较低导致安装失败
解决方案:使用命令:python -m pip install --upgrade pip
来升级pip版本即可解决
Django配置数据库连接
Django支持MySQL 5.6及更高版本
,同时推荐使用mysqlclient
作为数据库引擎
•(1)新建项目Django_demo_db
•(2)在项目目录下的settings.py
文件进行数据库配置
•配置如下:
# 数据库配置默认使用 大写
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 将数据库改为MySQL 默认为Django自带的sqlite3
'NAME': 'django_demo1', # 数据库名称
'HOST': '127.0.0.1', # 本地地址 默认为127.0.0.1
'PORT': 3306, # 端口号 MySQL默认端口为3306
'USER': 'root', # 用户名 自己设置的
'PASSWORD': 'root' # 用户密码 自己设置
}
}
•在启动项目前,需要先开启MySQL服务
,可以通过系统服务、命令行开启,也可以使用集成工具如PHPStudy开启
,前提是已将安装MySQL或者使用PHPStudy安装,然后可以使用Navicat、SQLYog等数据库可视化工具
操作MySQL数据库
注意
•如果你对上述安装过程有疑问或者没有上述安装包,可在博文下留言,博主第一时间看到会回复并免费发送以上文件
•在这里我们使用SQLYog这个可视化工具来操作MySQL数据库
•开启服务后需要在SQLYog中创建一个名为django_demo1
的数据库,同时执行python manage.py migrate
映射数据库,完成后即可在SQLYog中参看
创建数据库:
使用命令映射数据库后查看SQLYog:
•显然,已经将Django自带的系统表映射到了数据库中,这是Django为了实现一些默认的业务逻辑而建立的,同时说明连接数据库已经成功
原生SQL操作数据库
•Django中操作数据库有两种方式:
第一种方式就是使用原生SQL语句操作,第二种就是使用ORM模型来操作。
•在Django中使用原生SQL语句操作其实就是使用Python DB API
的接口来操作的
•如果你使用的MySQL驱动是pymysql
,就是使用pymysql来操作的
•Django将数据库连接已经封装好了,只要在settings.py
文件中配置好数据库连接信息后,即可直接使用Django封装好的接口操作数据库
•创建表book,如下:
CREATE TABLE `book` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`price` float(10,2) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
•也可以使用可视化工具SQLYog创建:
•通过命令插入两条数据:
insert into book values(null, 'Python', 88), (null, 'Java', 99);
•新建名为book的app,book下的views.py文件如下:
from django.http import HttpResponse
from django.db import connection
def index(request):
# 获取对象
cursor = connection.cursor()
# 执行SQL语句
cursor.execute('select * from book')
# 获取1条数据
data = cursor.fetchone()
print(data)
# 获取多条数据
data = cursor.fetchall()
print(data)
return HttpResponse('图书首页')
•网页显示:
此时访问http://127.0.0.1:8000/,控制台打印为:
(1, 'Python', 88.0)
((2, 'Java', 99.0),)
由控制台打印看看出:
•在获取一条数据时,返回一个元组
•获取所有数据时,返回由元组组成的元组,一个元组代表一条数据
•execute()
、fetchone()
和fetchall()
方法都是Python DB API
规范中定义好的,任何使用Python来操作MySQL的驱动程序都应该遵循该规范,因为不管是使用pymysql
或者是mysqlclient
或者是mysqldb
驱动,接口都是一样的
•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语句,还可以根据需要传递参数,定义parameters属性即可 |
fetchone | 在执行了查询操作以后,获取第一条数据 |
fetchmany(size) | 在执行查询操作以后,获取多条数据,具体是多少条要看传的size参数,如果不传size参数,那么默认是获取第一条数据 |
fetchall | 获取所有满足sql语句的数据 |
•测试上述操作如下:
from django.http import HttpResponse
from django.db import connection
def index(request):
# 获取游标对象
cursor = connection.cursor()
# 执行SQL语句
cursor.execute('select * from book')
# 获取1条数据
data = cursor.fetchone()
print(data)
# 获取多条数据
data = cursor.fetchall()
print(data)
print(cursor.rowcount)
return HttpResponse('图书首页')
访问http://127.0.0.1:8000/,控制台打印为:
(1, 'Python', 88.0)
((2, 'Java', 99.0),)
2
案例:图书馆系统(Django简易版)
•使用原生SQL方式
实现一个图书管理系统,完成图书的增删查和前端页面展示
图书首页
•book下的views.py视图文件如下:
from django.shortcuts import render
from django.db import connection
def index(request):
cursor = connection.cursor()
cursor.execute('select * from book')
books = cursor.fetchall()
context = {
'books': books
}
return render(request, 'index.html', context=context)
•book下新建urls.py路由文件:
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index')
]
•项目目录下的urls.py文件如下:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('book/', include('book.urls')),
]
•项目目录下新建templates目录,在templates下新建index.html文夹如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图书首页</title>
</head>
<body>
<ul>
<li><a href="{% url 'index' %}">首页</a></li>
<li><a href="#">发布图书</a></li>
</ul>
<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>
</body>
</html>
•项目目录下settings.py文件中修改模板路径如下:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')], # 修改模板路径
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
•启动项目并访问http://127.0.0.1:8000/book/,网页显示如下:
•由上可以看出:已显示图书的基本信息(数据库中所保存的)
图书添加
•下面使用的多个模板有公共部分,可以使用模板继承优化模板结构,新建base.html
如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<ul>
<li><a href="{% url 'index' %}">首页</a></li>
<li><a href="{% url 'add_book' %}">发布图书</a></li>
</ul>
{% block content %}
{% endblock %}
</body>
</html>
•index.html文件如下:
{% extends 'base.html' %}
{% block title %}
图书首页
{% endblock %}
{% 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 title %}
添加图书
{% endblock %}
{% block content %}
<form action="" method="post">
图书名称:<input type="text" name="name"><br>
图书价格:<input type="text" name="price"><br>
<input type="submit" value="提交">
</form>
{% endblock %}
•book下的views.py视图文件如下:
from django.shortcuts import render
from django.db import connection
def index(request):
cursor = connection.cursor()
cursor.execute('select * from book')
books = cursor.fetchall()
context = {
'books': books
}
return render(request, 'index.html', context=context)
def add_book(request):
return render(request, 'add_book.html')
•book下的urls.py路由文件如下:
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('add_book/', views.add_book, name='add_bbok')
]
•启动项目并访问http://127.0.0.1:8000/book/,网页显示如下:
•访问报错,提示CSRF验证失败
、请求已中止
Django框架为表单提交设置了CSRF保护
,解决办法有两种:
(1)关闭Django框架的CSRF保护,即在项目目录下settings.py
中移除CSRF保护中间件即可:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
(2)模板中增加CSRF标签:
{% extends 'base.html' %}
{% block title %}
添加图书
{% endblock %}
{% block content %}
<form action="" method="post">
{% csrf_token %}
图书名称:<input type="text" name="name"><br>
图书价格:<input type="text" name="price"><br>
<input type="submit" value="提交">
</form>
{% endblock %}
•网页显示如下:
•由上可看出,网页可以正常访问,并且模板中加载了隐藏的CSRF Token
,推荐使用第二种方式
•在views.py视图文件中实现图书提交之后的代码逻辑,代码如下:
from django.shortcuts import render, redirect, reverse
from django.db import connection
def get_cursor():
return connection.cursor()
def index(request):
cursor = get_cursor()
cursor.execute('select * from book')
books = cursor.fetchall()
context = {
'books': books
}
return render(request, 'index.html', context=context)
def add_book(request):
if request.method == 'POST':
name = request.POST.get('name')
price = request.POST.get('price')
cursor = get_cursor()
cursor.execute("insert into book(`name`, `price`) values('%s', '%s')" % (name, price))
return redirect(reverse('index'))
else:
return render(request, 'add_book.html')
•代码测试如下:
•数据库显示如下:
•显然,此时可以正常添加数据,并且添加成功后重定向到首页;
•对于添加add_book路由来说,如果请求方法为GET
,直接渲染模板,如果请求方法为POST
,则进行数据提交,提交后重定向到首页模板并将数据添加到数据库
图书详情
•book下的视图函数views.py如下:
from django.shortcuts import render, redirect, reverse
from django.db import connection
def get_cursor():
return connection.cursor()
def index(request):
cursor = get_cursor()
cursor.execute('select * from book')
books = cursor.fetchall()
context = {
'books': books
}
return render(request, 'index.html', context=context)
def add_book(request):
if request.method == 'POST':
name = request.POST.get('name')
price = request.POST.get('price')
cursor = get_cursor()
cursor.execute("insert into book(`name`, `price`) values('%s', '%s')" % (name, price))
return redirect(reverse('index'))
else:
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)
•book下的路由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'),
]
•templates目录下的index.html如下:
{% extends 'base.html' %}
{% block title %}
图书首页
{% endblock %}
{% block content %}
<table>
<tr>
<th>序号</th>
<th>图书名称</th>
<th>图书价格</th>
</tr>
{% for book in books %}
<tr>
<td>{{ forloop.counter }}</td>
<td><a href="{% url 'book_detail' book_id=book.0 %}">{{ book.1 }}</a></td>
<td>{{ book.2 }}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
•templates目录下新建的book_detail.html如下:
{% extends 'base.html' %}
{% block content %}
<table>
<tr>
<th>序号</th>
<th>图书名称</th>
<th>图书价格</th>
</tr>
<tr>
<td>{{ book.0 }}</td>
<td>{{ book.1 }}</td>
<td>{{ book.2 }}</td>
</tr>
</table>
{% endblock %}
•网页显示:
•查看图书详情成功
图书删除
•views.py中实现删除图书如下:
from django.shortcuts import render, redirect, reverse
from django.db import connection
def get_cursor():
return connection.cursor()
def index(request):
cursor = get_cursor()
cursor.execute('select * from book')
books = cursor.fetchall()
context = {
'books': books
}
return render(request, 'index.html', context=context)
def add_book(request):
if request.method == 'POST':
name = request.POST.get('name')
price = request.POST.get('price')
cursor = get_cursor()
cursor.execute("insert into book(`name`, `price`) values('%s', '%s')" % (name, price))
return redirect(reverse('index'))
else:
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')
•book下的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下的book_detail.html如下:
{% extends 'base.html' %}
{% block content %}
<table>
<tr>
<th>序号</th>
<th>图书名称</th>
<th>图书价格</th>
<th>操作/删除</th>
</tr>
<tr>
<td>{{ book.0 }}</td>
<td>{{ book.1 }}</td>
<td>{{ book.2 }}</td>
<td><a href="{% url 'book_delete' book_id=book.0 %}">删除图书</a></td>
</tr>
</table>
{% endblock %}
•网页显示如下:
•数据库显示如下:
•显然删除图书成功
图书修改
•views.py中实现修改图书业务逻辑:
from django.shortcuts import render, redirect, reverse
from django.db import connection
def get_cursor():
return connection.cursor()
def index(request):
cursor = get_cursor()
cursor.execute('select * from book')
books = cursor.fetchall()
context = {
'books': books
}
return render(request, 'index.html', context=context)
def add_book(request):
if request.method == 'POST':
name = request.POST.get('name')
price = request.POST.get('price')
cursor = get_cursor()
cursor.execute("insert into book(`name`, `price`) values('%s', '%s')" % (name, price))
return redirect(reverse('index'))
else:
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')
def update_book(request, book_id):
cursor = get_cursor()
if request.method == 'POST':
name = request.POST.get('name')
price = request.POST.get('price')
book_id = request.POST.get('book_id')
cursor.execute("update book set name='%s', price='%s'where id='%s'" % (name, price, book_id))
return redirect(reverse('index'))
else:
cursor.execute("select * from book where id=%s" % book_id)
book = cursor.fetchone()
context = {
'book': book
}
return render(request, 'book_update.html', context=context)
•book下的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'),
path('update_book/<int:book_id>', views.update_book, name='update_book'),
]
•templates下的index.html如下:
{% extends 'base.html' %}
{% block title %}
图书首页
{% endblock %}
{% block content %}
<table>
<tr>
<th>序号</th>
<th>图书名称</th>
<th>图书价格</th>
<th>修改信息</th>
</tr>
{% for book in books %}
<tr>
<td>{{ forloop.counter }}</td>
<td><a href="{% url 'book_detail' book_id=book.0 %}">{{ book.1 }}</a></td>
<td>{{ book.2 }}</td>
<td><a href="{% url 'update_book' book_id=book.0 %}">修改</a></td>
</tr>
{% endfor %}
</table>
{% endblock %}
•templates下新建book_update.html如下:
{% extends 'base.html' %}
{% block content %}
<form action="" method="post">
{% csrf_token %}
<table>
<tr>
<th>序号</th>
<th>图书名称</th>
<th>图书价格</th>
</tr>
<tr>
<td>{{ book.0 }}</td>
<td><input type="hidden" value="{{ book.0 }}" name="book_id"></td>
<td><input type="text" value="{{ book.1 }}" name="name"></td>
<td><input type="text" value="{{ book.2 }}" name="price"></td>
<td><input type="submit" value="提交"></td>
</tr>
</table>
</form>
{% endblock %}
•网页显示如下:
•数据库显示如下:
•显示已经实现修改图书的功能