ORM對(duì)象關(guān)系映射(Object Relational Mapping)用于實(shí)現(xiàn)面向?qū)ο缶幊陶Z(yǔ)言里不同類型系統(tǒng)的數(shù)據(jù)之間的轉(zhuǎn)換。ORM 是通過使用描述對(duì)象和數(shù)據(jù)庫(kù)之間的映射的元數(shù)據(jù),將程序中的對(duì)象自動(dòng)持久化到數(shù)據(jù)庫(kù)中。
- ORM 在業(yè)務(wù)邏輯層和數(shù)據(jù)庫(kù)層之間充當(dāng)了橋梁的作用。
- Django 模型使用自帶的 ORM。
本地環(huán)境
- python3.6.5
- Django2.2.17
1. 修改Django項(xiàng)目的數(shù)據(jù)庫(kù)配置
- 修改settings.py中DATABASES數(shù)據(jù)庫(kù)配置
DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': BASE_DIR / 'db.sqlite3',
# }
'default': {
'ENGINE': 'django.db.backends.mysql', # 數(shù)據(jù)庫(kù)引擎
'NAME': 'ma', # 數(shù)據(jù)庫(kù)名稱
'HOST': '127.0.0.1', # 數(shù)據(jù)庫(kù)地址
'PORT': 3306, # 數(shù)據(jù)庫(kù)端口
'USER': 'root', # 數(shù)據(jù)庫(kù)用戶名
'PASSWORD': '123456', # 數(shù)據(jù)庫(kù)密碼
}
}
- 修改與 settings.py 同級(jí)目錄下的 init.py 中引入模塊和進(jìn)行配置。否則啟動(dòng)服務(wù)時(shí)會(huì)報(bào)錯(cuò)
import pymysql
pymysql.install_as_MySQLdb()

- 因?yàn)?ORM 無法操作到數(shù)據(jù)庫(kù)級(jí)別,只能操作到數(shù)據(jù)表,所以如果要操作新的數(shù)據(jù)庫(kù),需提前新建一個(gè)數(shù)據(jù)庫(kù)。
- 進(jìn)入mysql服務(wù)后執(zhí)行如下語(yǔ)句:
create database ma default charset=utf8mb4;#設(shè)置字符集為uftmb4后排序規(guī)則默認(rèn)為uft8mb4_general_ci; - 或者通過桌面客戶端新建數(shù)據(jù)庫(kù)

2. 定義模型
新建一個(gè)app
Django 規(guī)定,如果要使用模型,必須要?jiǎng)?chuàng)建一個(gè) app。
- 進(jìn)入項(xiàng)目目錄執(zhí)行命令:
django-admin startapp Account -
執(zhí)行成功后,生成的app數(shù)據(jù)如下
模型app的目錄結(jié)構(gòu)
創(chuàng)建模型
修改Account/models.py文件:
- 類名:代表數(shù)據(jù)庫(kù)表名,且繼承了models.Model
- 類屬性:代表數(shù)據(jù)表中的字段。數(shù)據(jù)類型則由IntegerField(對(duì)應(yīng)數(shù)據(jù)庫(kù)的int類型),CharField(對(duì)應(yīng)數(shù)據(jù)庫(kù)的varchar類型,max_length 參數(shù)限定長(zhǎng)度),DateTimeFiled(對(duì)應(yīng)數(shù)據(jù)庫(kù)的datetime類型,日期顯示為年-月-日 時(shí):分:秒),DateField(相當(dāng)于數(shù)據(jù)庫(kù)date類型,日期精確到年-月-日)
from django.db import models
# Create your models here.
class User(models.Model):
nickname = models.CharField(max_length=20)
age = models.IntegerField()
birthday = models.DateField()
create_at = models.DateTimeField()
updated_at = models.DateTimeField()
添加模型配置
- 修改settings.py 中找到INSTALLED_APPS,添加新創(chuàng)建的模型app
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'Account', # 添加此項(xiàng)
)
執(zhí)行自帶的遷移文件migrate
- 項(xiàng)目目錄下運(yùn)行:
python manage.py migrate,執(zhí)行遷移后會(huì)在當(dāng)前路徑下生成db.sqlite3的數(shù)據(jù)庫(kù)文件。

3. 生成遷移文件并執(zhí)行遷移
- 生成遷移文件:
python manage.py makemigrations {appName},執(zhí)行該命令后Account目錄下的migrations文件夾會(huì)生成對(duì)應(yīng)遷移內(nèi)容

- 執(zhí)行遷移:
python manage.py migrate {appName},執(zhí)行該命令后會(huì)創(chuàng)建表結(jié)構(gòu)等。
-
執(zhí)行命令后報(bào)錯(cuò)mysqlclient版本過低,原因是 MySQLclient 目前只支持到 Python3.4,因此如果使用的更高版本的 python,需要修改如下:
報(bào)錯(cuò)mysqlclient版本過低 -
修改文件D:\Python3\Lib\site-packages\django\db\backends\mysql\base.py文件:
修改Django包中對(duì)mysqlclient版本的限制導(dǎo)致執(zhí)行遷移報(bào)錯(cuò)問題
- 遷移執(zhí)行成功后生成的數(shù)據(jù)庫(kù)表如下:


- django_content_type表和auth_permission表記錄模型的CRUD
-
創(chuàng)建app,生成遷移文件,執(zhí)行遷移之后在django_content_type表會(huì)新增該app下的模型model記錄,在auth_permission表中對(duì)每一個(gè)model就會(huì)新增4條CRUD記錄。
django_content_type表

自定義數(shù)據(jù)庫(kù)表名和字段名
- Django中生成的數(shù)據(jù)庫(kù)表名默認(rèn)為{appname}_類名,如果想生成的表名直接是數(shù)據(jù)庫(kù)類名的話需要做如下修改:
from django.db import models
# Create your models here.
class User(models.Model):
# 在Meta 類中通過db_table自定義數(shù)據(jù)庫(kù)表名
class Meta:
db_table = 'user'
# 通過 db_column 自定義數(shù)據(jù)庫(kù)字段名
nickname = models.CharField(max_length=20, db_column='nickname')
age = models.IntegerField(db_column='age')
birthday = models.DateField(auto_now=True)
create_at = models.DateTimeField(auto_now=True)
updated_at = models.DateTimeField(auto_now=True)
- 然后重新生成遷移文件并執(zhí)行遷移即可生效。
操作數(shù)據(jù)庫(kù)CRUD
1. 添加數(shù)據(jù)
保存并提交數(shù)據(jù):create(),save()
方式一:通過 ORM 提供的 objects 提供的方法 create() 來實(shí)現(xiàn)(推薦)
方式二:模型類實(shí)例化對(duì)象.save()
- 在app同級(jí)目錄Account,views.py中添加數(shù)據(jù):
# views.py
from Account.models import User
from django.http import HttpResponse
def add_user(request):
user = User.objects.create(nickname="test", age=1, birthday="2020-9-25")
return HttpResponse("<p>添加用戶數(shù)據(jù)成功!</p>")
def add_user2(request):
user = User(nickname="test", age=1, birthday="2020-9-25")
user.save()
return HttpResponse("<p>添加用戶數(shù)據(jù)成功!</p>")
- 修改django_demo/urls.py文件添加路由映射:
from django.contrib import admin
from django.urls import path
from django.conf.urls import url
from . import views
from Account import views as account_views
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$', views.hello),
url('add_user/', account_views.add_user),
]
- 訪問http://loacalhost:8000/add_user,提示新增數(shù)據(jù)成功

-
查看數(shù)據(jù)庫(kù)中的數(shù)據(jù)如下
新增user數(shù)據(jù)
2. 查詢數(shù)據(jù)
查詢語(yǔ)句:
User.objects.filter(age=1)#返回?cái)?shù)組,當(dāng)查詢的是結(jié)果為空時(shí)返回空數(shù)組: <QuerySet [<User: User object (6)>, <User: User object (9)>]>,其中6和9指的是符合要求的所在行idUser.objects.get(age=1)# 返回一個(gè)對(duì)象User object (7),當(dāng)查詢到的數(shù)據(jù)為空或者查詢到多條數(shù)據(jù)時(shí)會(huì)報(bào)錯(cuò),其中7指的是符合要求的數(shù)據(jù)所在行idmodel_to_dict,將queryset對(duì)象轉(zhuǎn)化為dict類型,
model_to_dict(instance) for instance in queryset修改opdb_user.py文件:
from django.forms.models import model_to_dict
# 查詢數(shù)據(jù)庫(kù)表user
def query_user(request):
# 獲取所有用戶,orm查詢數(shù)據(jù)庫(kù)返回的是queryset對(duì)象
queryset = User.objects.all()
# 將queryset對(duì)象轉(zhuǎn)化為dict型數(shù)組
users = [model_to_dict(instance) for instance in queryset]
response = ‘’
for user in users:
response += "nickname: {}-----age:{}----birthday: {}<br/>".format(user.nickname, user.age, user.birthday)
return HttpResponse(response)
- 修改urls.py文件,新增url映射關(guān)系:url('query_user/', opdb_user.query_user),
-
頁(yè)面效果如下
顯示所有的user -
User.objects.get(age=1)當(dāng)查詢到的條數(shù)大于1時(shí),報(bào)錯(cuò)如下:
get()查詢到的條數(shù)不為1時(shí)報(bào)錯(cuò)
3. 更新數(shù)據(jù)
修改數(shù)據(jù)可以使用 save() 或 update()
- 修改opdb_user.py文件:
# 更新數(shù)據(jù)
def update_user(request):
# 方式1
user = User.objects.get(id=1)
user.nickname = "哈哈哈" # 并且create_at和updated_at會(huì)更新為當(dāng)前時(shí)間
user.save()
# 方式2
User.objects.filter(id=3).update(nickname="呵呵呵", age=100) # create_at和updated_at不會(huì)更新
return HttpResponse("<p>修改數(shù)據(jù)成功!</p>")
- 修改urls.py文件添加url映射:url('update_user/', opdb_user.update_user),
- 頁(yè)面訪問http://localhost:8000/update_user/,并查看數(shù)據(jù)庫(kù)效果
4. 刪除數(shù)據(jù)
可以刪除單個(gè)實(shí)例對(duì)象:
User.objects.get(pk=pk).delete()
也可以刪除實(shí)例結(jié)果集:User.objects.filter(age=10).delete()
- 修改opdb_user.py文件
# 刪除數(shù)據(jù)
def delete_user(request):
user = User.objects.filter(age=100) # 當(dāng)查詢的結(jié)果為空時(shí),執(zhí)行刪除操作不會(huì)報(bào)錯(cuò)
user.delete()
return HttpResponse("<p>刪除age=100的所有用戶</p>")
- 修改urls.py文件添加url映射:url('delete_user/', opdb_user.delete_user),
- 頁(yè)面訪問http://localhost:8000/delete_user/,并查看數(shù)據(jù)庫(kù)效果






