1.数据库操作相关软件和包介绍
2.Django使用原生SQL语句操作数据库
Django配置连接数据库:
要在 settings.py 文件中做好数据库相关的配置就 可以了。示例代码如下:
DATABASES = {
'default': {
# 数据库引擎(是mysql还是oracle等)
'ENGINE': 'django.db.backends.mysql',
# 数据库的名字
'NAME': 'DjangoDB',
# 连接mysql数据库的用户名
'USER': 'root',
# 连接mysql数据库的密码
'PASSWORD': 'root',
# mysql数据库的主机地址
'HOST': '127.0.0.1',
# mysql数据库的端口号
'PORT': '3306',
}
}
在 Django 中操作数据库有两种方式。第一种方式就是使用原生 sql 语句操作,第二种就是使 用 ORM 模型来操作。
在 settings.py 中配置好了数据库连接信息后直接使 用 Django 封装好的接口就可以操作了。示例代码如下:
from django.shortcuts import render
from django.template.loader import render_to_string
from django.http import HttpResponse
from django.db import connection
def index(request):
# html = render_to_string("index.html")
# return HttpResponse(html)
cursor=connection.cursor()
#cursor.execute("insert into book(id,name,author) values(null,'三国演义','罗贯中')")
cursor.execute("select * from book")
rows=cursor.fetchall()
for row in rows:
print(row)
return render(request,'index.html')
以上的 execute 以及 fetchall 方法都是 Python DB API 规范中定义好的。任何使用 Python 来操 作 MySQL 的驱动程序都应该遵循这个规范。所以不管是使用 pymysql 或者是 mysqlclient 或者 是 mysqldb ,他们的接口都是一样的。
cursor.execute("insert into book(id,name,author) values(null,'三国演义','罗贯中')")
# null是因为id设置为了自增
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 语句的数据。
cursor.execute("select id,name,author from book")
rows=cursor.fetchone()
rows=cursor.fetchmany(2)
rows=cursor.fetchall()
3.图书管理系统案例1
front.views
from django.shortcuts import render,redirect,reverse
from django.db import connection
def get_corsor():
return connection.cursor()
def index(request):
cursor = get_corsor()
cursor.execute("select id,name,author from book")
books = cursor.fetchall()
# [(1,'三国演义','罗贯中'),()....]
return render(request,'index.html',context={"books":books})
def add_book(request):
if request.method == 'GET':
return render(request,'add_book.html')
else:
name = request.POST.get("name")
author = request.POST.get("author")
cursor = get_corsor()
cursor.execute("insert into book(id,name,author) values(null,'%s','%s')" % (name,author))
return redirect(reverse('index'))
def book_detail(request,book_id):
cursor = get_corsor()
cursor.execute("select id,name,author from book where id=%s" % book_id)
book = cursor.fetchone()
return render(request,'book_detail.html',context={"book":book})
def delete_book(request):
if request.method == 'POST':
book_id = request.POST.get('book_id')
cursor = get_corsor()
cursor.execute("delete from book where id=%s" % book_id)
return redirect(reverse('index'))
else:
raise RuntimeError("删除图书的method错误!")
urls
from django.urls import path
from front 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('delete_book/',views.delete_book,name='delete_book')
]
index.html
{% extends 'base.html' %}
{% block content %}
<table>
<thead>
<tr>
<th>序号</th>
<th>书名</th>
<th>作者</th>
</tr>
</thead>
<tbody>
{% 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 %}
</tbody>
</table>
{% endblock %}
base.css
*{
margin: 0;
padding: 0;
}
.nav{
background: #3a3a3a;
height: 65px;
overflow: hidden;
}
.nav li{
float: left;
list-style: none;
margin: 0 20px;
line-height: 65px;
}
.nav li a{
color: #fff;
text-decoration: none;
}
.nav li a:hover{
color: lightblue;
}
base.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图书管理系统</title>
<link rel="stylesheet" href="{% static 'front/base.css' %}">
</head>
<body>
<nav>
<ul class="nav">
<li><a href="/">首页</a></li>
<li><a href="{% url 'add_book' %}">发布图书</a></li>
</ul>
</nav>
{% block content %}{% endblock %}
</body>
</html>
4.图书管理系统案例2
add_book.html
{% extends 'base.html' %}
{% block content %}
<form action="" method="post">
<table>
<tbody>
<tr>
<td>书名:</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td>作者:</td>
<td><input type="text" name="author"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="提交"></td>
</tr>
</tbody>
</table>
</form>
{% endblock %}
book_detail
{% extends 'base.html' %}
{% block content %}
<p>书名:{{ book.1 }}</p>
<p>作者:{{ book.2 }}</p>
<form action="{% url 'delete_book' %}" method="post">
<input type="hidden" name="book_id" value="{{ book.0 }}">
<input type="submit" value="删除按钮">
</form>
{% endblock %}
5.ORM模型介绍
随着项目越来越大,采用写原生SQL的方式在代码中会出现大量的SQL语句,那么问题就出现了:
- SQL语句重复利用率不高,越复杂的SQL语句条件越多,代码越长。会出现很多相近的SQL语 句。
- 很多SQL语句是在业务逻辑中拼出来的,如果有数据库需要更改,就要去修改这些逻辑,这会 很容易漏掉对某些SQL语句的修改。
- 写SQL时容易忽略web安全问题,给未来造成隐患。SQL注入。
ORM ,全称 Object Relational Mapping ,对象关系映射
通过 ORM 我们可以通过类的 方式去操作数据库,而不用再写原生的SQL语句。
通过把表映射成类,把行作实例,把字段作为属性
ORM 在执行对象操作的时候最终还是会把对应的操作转换为数据库原生语句。
使用 ORM 有许 多优点:
- 易用性:使用 ORM 做数据库的开发可以有效的减少重复SQL语句的概率,写出来的模型也更 加直观、清晰。
- 性能损耗小: ORM 转换成底层数据库操作指令确实会有一些开销。但从实际的情况来看,这 种性能损耗很少(不足5%),只要不是对性能有严苛的要求,综合考虑开发效率、代码的阅
读性,带来的好处要远远大于性能损耗,而且项目越大作用越明显。- 设计灵活:可以轻松的写出复杂的查询。
- 可移植性: Django 封装了底层的数据库实现,支持多个关系数据库引擎,包括流行 的 MySQL 、 PostgreSQL 和 SQLite 。可以非常轻松的切换数据库。
ORM 模型一般都是放在 app 的 models.py 文件中。
每个 app 都可以拥有自己的模型。
并且如果这个模型想要映射到数据库中
那么这个 app 必须要放在 settings.py 的 INSTALLED_APP 中进行安装。
以下是写一个简单的书籍 ORM 模型。示例代码如下:
from django.db import models
class Book(models.Model):
name = models.CharField(max_length=20,null=False)
author = models.CharField(max_length=20,null=False)
pub_time = models.DateTimeField(default=datetime.now)
price = models.FloatField(default=0)
以上便定义了一个模型。
这个模型继承自 django.db.models.Model ,如果这个模型想要映射到数据库中就必须继承自这个类。
这个模型以后映射到数据库中,表名是模型名称的小写形式, 为 book 。 在这个表中,有四个字段.
一个为 name这个字段是保存的是书的名称, 是 varchar 类型,最长不能超过20个字符,并且不能为空。
第二个字段是作者名字类型,同样也是varchar 类型,长度不能超过20个。
第三个是出版时间,数据类型是 datetime 类型,默认是保存这本书籍的时间。
第四个是这本书的价格,是浮点类型。
还有一个字段我们没有写,就是主键 id ,在 django中,如果一个模型没有定义主键,那么将会 自动生成一个自动增长的 int 类型的主键,并且这个主键的名字就叫做 id 。
6.创建和映射ORM模型
映射模型到数据库中: 将 ORM 模型映射到数据库中,总结起来就是以下几步:
- 在 settings.py 中,配置好 DATABASES ,做好数据库相关的配置。
- 在 app 中的 models.py 中定义好模型,这个模型必须继承自 django.db.models
- 将这个 app 添加到 settings.py 的 INSTALLED_APP 中。
- 在命令行终端,进入到项目所在的路径,然后执行命令 python manage.py makemigrations 来 生成迁移脚本文件。
- 同样在命令行中,执行命令 python manage.py migrate 来将迁移脚本文件映射到数据库中。
models.py
from django.db import models
# 如果要将一个普通的类变成一个可以映射到数据库中的ORM模型
# 那么必须要将父类设置为models.Model或者他的子类
class Book(models.Model):
# 1. id:int类型,是自增长的。
id = models.AutoField(primary_key=True)
# 2. name:varchar(100),图书的名字
name = models.CharField(max_length=100,null=False)
# 3. author:varchar(100),图书的作者
author = models.CharField(max_length=100,null=False)
# 4. price:float,图书的价格
price = models.FloatField(null=False,default=0)
class Publisher(models.Model):
name = models.CharField(max_length=100,null=False)
address = models.CharField(max_length=100,null=False)
# 1. 使用makemigrations生成迁移脚本文件
# python manage.py makemigrations
# 2. 使用migrate将新生成的迁移脚本文件映射到数据库中
# python manage.py migrate
7.ORM模型基本的增删改查
urls
from django.urls import path
from book import views
urlpatterns = [
path('', views.index),
]
views.py
from django.shortcuts import render
from .models import Book
from django.http import HttpResponse
def index(request):
# 1. 使用ORM添加一条数据到数据库中
# book = Book(name='西游记',author='吴承恩',price=100)
# book.save()
# 2. 查询
# 2.1. 根据主键进行查找
# primary key
# book = Book.objects.get(pk=2)
# print(book)
# 2.2. 根据其他条件进行查找
# books = Book.objects.filter(name='三国演义').first()
# print(books)
# 3. 删除数据
# book = Book.objects.get(pk=1)
# book.delete()
# 4. 修改数据
book = Book.objects.get(pk=2)
book.price = 200
book.save()
return HttpResponse("图书添加成功!")