1、數據庫
MySQL驅動程序安裝
我們使用Django來操作MySQL,實際上底層還是通過Python來操作的。因此我們想要用Django來操作MySQL,首先還是需要安裝一個驅動程序。在Python3中,驅動程序有多種選擇。比如有pymysql以及mysqlclient等。這裏我們就使用mysqlclient來操作。mysqlclient安裝非常簡單。只需要通過pip install mysqlclient
即可安裝。
常見MySQL驅動介紹:
- MySQL-python:也就是MySQLdb。是對C語言操作MySQL數據庫的一個簡單封裝。遵循了Python DB API v2
但是隻支持Python2,目前還不支持Python3。 - mysqlclient:是MySQL-python的另外一個分支。支持Python3 並且修復了一些bug。
- pymysql:純Python實現的一個驅動。因爲是純Python編寫的,因此執行效率不如MySQL-python。並且也因爲是純Python編寫的,因此可以和Python代碼無縫銜接。
- 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
連接映射數據庫:
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對象常用接口
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參數。fetchone
:在執行了查詢操作以後,獲取第一條數據。fetchmany(size)
:在執行查詢操作以後,獲取多條數據。具體是多少條要看傳的size參數。如果不傳size參數,那麼默認是獲取第一條數據。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、實戰案例:圖書管理系統
需求
完成圖書的增刪改查,以及前端的頁面的展示
項目文件目錄如下:
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。可以非常輕鬆的切換數據庫。