Django--模型&數(shù)據(jù)庫(kù)CRUD

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()
未引入pymysql時(shí)報(bào)錯(cuò)如下
  • 因?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ù)
新建數(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ù)文件。
執(zhí)行默認(rèn)的遷移文件

3. 生成遷移文件并執(zhí)行遷移

  1. 生成遷移文件:python manage.py makemigrations {appName},執(zhí)行該命令后Account目錄下的migrations文件夾會(huì)生成對(duì)應(yīng)遷移內(nèi)容
生成遷移文件
  1. 執(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ò)問題
  1. 遷移執(zhí)行成功后生成的數(shù)據(jù)庫(kù)表如下:
生成的account_user表
account_user表結(jié)構(gòu)定義
  1. 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表
auth_permission表

自定義數(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),
]
image.png
  • 查看數(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指的是符合要求的所在行id

  • User.objects.get(age=1) # 返回一個(gè)對(duì)象User object (7),當(dāng)查詢到的數(shù)據(jù)為空或者查詢到多條數(shù)據(jù)時(shí)會(huì)報(bào)錯(cuò),其中7指的是符合要求的數(shù)據(jù)所在行id

  • model_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ù)效果
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容