一、ORM
ORM概念
對象關系映射(Object Relational Mapping,簡稱ORM)模式是一種為了解決面向對象與關系數(shù)據(jù)庫存在的互不匹配的現(xiàn)象的技術。
簡單的說,ORM是通過使用描述對象和數(shù)據(jù)庫之間映射的元數(shù)據(jù),將程序中的對象自動持久化到關系數(shù)據(jù)庫中。
ORM在業(yè)務邏輯層和數(shù)據(jù)庫層之間充當了橋梁的作用。
ORM由來
讓我們從O/R開始。字母O起源于"對象"(Object),而R則來自于"關系"(Relational)。
幾乎所有的軟件開發(fā)過程中都會涉及到對象和關系數(shù)據(jù)庫。在用戶層面和業(yè)務邏輯層面,我們是面向對象的。當對象的信息發(fā)生變化的時候,我們就需要把對象的信息保存在關系數(shù)據(jù)庫中。
按照之前的方式來進行開發(fā)就會出現(xiàn)程序員會在自己的業(yè)務邏輯代碼中夾雜很多SQL語句用來增加、讀取、修改、刪除相關數(shù)據(jù),而這些代碼通常都是重復的。
ORM的優(yōu)勢
ORM解決的主要問題是對象和關系的映射。它通常把一個類和一個表一一對應,類的每個實例對應表中的一條記錄,類的每個屬性對應表中的每個字段。
ORM提供了對數(shù)據(jù)庫的映射,不用直接編寫SQL代碼,只需像操作對象一樣從數(shù)據(jù)庫操作數(shù)據(jù)。
讓軟件開發(fā)人員專注于業(yè)務邏輯的處理,提高了開發(fā)效率。
ORM的劣勢
ORM的缺點是會在一定程度上犧牲程序的執(zhí)行效率。
ORM用多了SQL語句就不會寫了,關系數(shù)據(jù)庫相關技能退化...
ORM總結
ORM只是一種工具,工具確實能解決一些重復,簡單的勞動。這是不可否認的。
但我們不能指望某個工具能一勞永逸地解決所有問題,一些特殊問題還是需要特殊處理的。
但是在整個軟件開發(fā)過程中需要特殊處理的情況應該都是很少的,否則所謂的工具也就失去了它存在的意義。
Django框架中ORM示意圖


1. 創(chuàng)建項目test2
今天演示使用MySQL數(shù)據(jù)庫,這是Web項目首選的數(shù)據(jù)庫。
進入虛擬環(huán)境h1_django。
workon h1_django
在/home/python/pytest目錄下創(chuàng)建項目test2。
django-admin startproject test2


打開test2/settings.py文件,找到DATABASES項,默認使用SQLite3數(shù)據(jù)庫

修改為使用MySQL數(shù)據(jù)庫,代碼如下:
將引擎改為mysql,提供連接的主機HOST、端口PORT、數(shù)據(jù)庫名NAME、用戶名USER、密碼PASSWORD。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'test2', #數(shù)據(jù)庫名字,
'USER': 'root', #數(shù)據(jù)庫登錄用戶名
'PASSWORD': 'mysql', #數(shù)據(jù)庫登錄密碼
'HOST': 'localhost', #數(shù)據(jù)庫所在主機
'PORT': '3306', #數(shù)據(jù)庫端口
}
}
注意:數(shù)據(jù)庫test2 Django框架不會自動生成,需要我們自己進入mysql數(shù)據(jù)庫去創(chuàng)建。
下面是手動創(chuàng)建數(shù)據(jù)庫,打開新終端,在命令行登錄mysql,創(chuàng)建數(shù)據(jù)庫test2。
注意:設置字符集為utf8
create database test2 charset=utf8;

返回第一個終端,進入test2目錄,創(chuàng)建應用booktest。
cd test2
python manage.py startapp booktest

將應用booktest注冊到項目中:打開test2/settings.py文件,找到INSTALLED_APPS項,加入如下代碼:
'booktest',

內(nèi)容復習
定義模型類
- 模型類被定義在"應用/models.py"文件中,此例中為"booktest/models.py"文件。
- 模型類必須繼承自Model類,位于包django.db.models中。
提示:對于重要數(shù)據(jù)使用邏輯刪除。
示例演示
接下來首先以"圖書-英雄"管理為例進行演示,復習一下之前的內(nèi)容。 1.打開booktest/models.py文件,定義模型類如下
from django.db import models
#定義圖書模型類BookInfo
class BookInfo(models.Model):
btitle = models.CharField(max_length=20)#圖書名稱
bpub_date = models.DateField()#發(fā)布日期
bread = models.IntegerField(default=0)#閱讀量
bcomment = models.IntegerField(default=0)#評論量
isDelete = models.BooleanField(default=False)#邏輯刪除
#定義英雄模型類HeroInfo
class HeroInfo(models.Model):
hname = models.CharField(max_length=20)#英雄姓名
hgender = models.BooleanField(default=True)#英雄性別
isDelete = models.BooleanField(default=False)#邏輯刪除
hcomment = models.CharField(max_length=200)#英雄描述信息
hbook = models.ForeignKey('BookInfo')#英雄與圖書表的關系為一對多,所以屬性定義在英雄模型類中
2.遷移 生成遷移文件
python manage.py makemigrations
生成遷移文件的時候出現(xiàn)錯誤,把數(shù)據(jù)庫切換成了mysql,需要安裝pymysql模塊之后,Django框架才可以操作mysql數(shù)據(jù)庫。安裝命令如下:
pip install pymysql

安裝成功之后,在test2/init.py文件中加上如下代碼:
import pymysql
pymysql.install_as_MySQLdb()
然后執(zhí)行如下命令
python manage.py makemigrations
python manage.py migrate

打開數(shù)據(jù)庫的命令行,查看當前所有表如下圖:

表bookinfo結構如:
默認值并不在數(shù)據(jù)庫層面生效,而是在django創(chuàng)建對象時生效。

表booktest_heroinfo結構如下:
Django框架會根據(jù)關系屬性生成一個關系字段,并創(chuàng)建外鍵約束。

3.測試數(shù)據(jù)
在數(shù)據(jù)庫命令行中,復制如下語句執(zhí)行,向booktest_bookinfo表中插入測試數(shù)據(jù):
insert into booktest_bookinfo(btitle,bpub_date,bread,bcomment,isDelete) values
('射雕英雄傳','1980-5-1',12,34,0),
('天龍八部','1986-7-24',36,40,0),
('笑傲江湖','1995-12-24',20,80,0),
('雪山飛狐','1987-11-11',58,24,0);

再復制如下語句執(zhí)行,向booktest_heroinfo表中插入測試數(shù)據(jù):
insert into booktest_heroinfo(hname,hgender,hbook_id,hcomment,isDelete) values
('郭靖',1,1,'降龍十八掌',0),
('黃蓉',0,1,'打狗棍法',0),
('黃藥師',1,1,'彈指神通',0),
('歐陽鋒',1,1,'蛤蟆功',0),
('梅超風',0,1,'九陰白骨爪',0),
('喬峰',1,2,'降龍十八掌',0),
('段譽',1,2,'六脈神劍',0),
('虛竹',1,2,'天山六陽掌',0),
('王語嫣',0,2,'神仙姐姐',0),
('令狐沖',1,3,'獨孤九劍',0),
('任盈盈',0,3,'彈琴',0),
('岳不群',1,3,'華山劍法',0),
('東方不敗',0,3,'葵花寶典',0),
('胡斐',1,4,'胡家刀法',0),
('苗若蘭',0,4,'黃衣',0),
('程靈素',0,4,'醫(yī)術',0),
('袁紫衣',0,4,'六合拳',0);
[圖片上傳失敗...(image-5b0062-1539520268469)]
4.定義視圖
打開booktest/views.py文件,定義視圖代碼如下:
from django.shortcuts import render,redirect
from booktest.models import *
from datetime import date
#查詢所有圖書并顯示
def index(request):
list=BookInfo.objects.all()
return render(request,'booktest/index.html',{'list':list})
#創(chuàng)建新圖書
def create(request):
book=BookInfo()
book.btitle = '流星蝴蝶劍'
book.bpub_date = date(1995,12,30)
book.save()
#轉向到首頁
return redirect('/')
#邏輯刪除指定編號的圖書
def delete(request,id):
book=BookInfo.objects.get(id=int(id))
book.delete()
#轉向到首頁
return redirect('/')
5.配置url 打開test2/urls.py文件,配置url如下:
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
#引入booktest的url配置
url(r'^',include('booktest.urls')),
]
在booktest應用下創(chuàng)建urls.py文件,代碼如下:
from django.conf.urls import url
from booktest import views
urlpatterns=[
url(r'^$',views.index),
url(r'^delete(\d+)/$',views.delete),
url(r'^create/$',views.create),
]
6.創(chuàng)建模板 打開test2/settings.py文件,配置模板查找目錄TEMPLATES的DIRS。
'DIRS': [os.path.join(BASE_DIR,'templates')],

創(chuàng)建templates/booktest/index.html文件。

模板代碼如下:
<html>
<head>
<title>復習案例</title>
</head>
<body>
<a href="/create/">創(chuàng)建</a>
<ul>
{%for book in list%}
<li>{{book.btitle}}--<a href="/delete{{book.id}}/">刪除</a></li>
{%endfor%}
</ul>
</body>
</html>