Python Django 學習 (二) 【Django 模型】
注: 由於自己排版確實很難看,本文開始使用markdown編輯,希望有所改善
官方定義
A model is the single, definitive source of information about your data. It contains the essential fields and behaviors of the data you’re storing. Generally, each model maps to a single database table.
一個模型是關於你的資料的單個的、確定的資訊源。它包含了你儲存資料的必要的列和行為,基本上,一個模型對映一個單個的資料庫表。
更改Django資料庫配置
由於原生的django使用的是sqlite3, 本人熟悉mysql 所以最後使用mysql。
注:本文接著上一篇文章來的,如果沒有相應的專案請按照上一篇內容操作一下。[Python Django 學習 (一) 【Django 框架初探】]
- 在 test_project專案中找到檔案 test_project/test_project/settings.py 找到如下程式碼
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } }
- 將上述程式碼註釋掉,新增如下程式碼:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mysql',#資料庫名字
'USER':'root',
'PASSWORD':'*****',
'HOST':'localhost',
'PORT':'3306',
}
}
- 確保一件事情,你的python3 的版本安裝了 pymysql 、mysqlclient 使用pip 安裝
pip3.6 install pymysql
pip3.6 install mysqlclient
# 我在安裝mysqlclient時出現了問題,到 https://www.lfd.uci.edu找的包自己安裝的
建立 test_app
在使用model時,官方文件說,“當你定了模型之後,你需要告訴Django你將使用這些模型。通過編輯setting.py中 INSTALL_APPS,將包含你的模型的app的名字放到裡面”
- 開啟 CMD 鍵入 如下指令:
python36 manage.py startapp test_app
將會在 test_project專案下 新建一個 test_app檔案目錄
作用說明
檔名 | 作用 |
---|---|
migrations | 將模型的更改,形成可執行的PY檔案,使用指令遷移到資料庫中 |
_init_.py | 標識當前檔案路徑是一個python包 |
admin.py | 可以在其中添加當前model,然後使用介面對資料庫進行操作 |
apps.py | 當前app 配置 |
models.py | 存放當前app存在的模型,與資料庫一一對應 |
tests.py | 存放當前app的測試 |
views.py | 存在當前app的頁面模板 |
- 將 test_app 新增到 test_project/test_project/settings.py檔案中,如下:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# new add
'test_app',
]
新增 testmodel 到 test_app中、遷移到資料庫
- 開啟 檔案 test_project/test_app/modes.py 更改程式碼如下:
from django.db import models
# Create your models here.
class TestModel(models.Model):
# django 有一個機制 在沒有設定自增主鍵的時候會自動建立一個主鍵,
test_name = models.CharField(max_length=100, default='no_name') # 字元型別的欄位 設定最大長度與預設值
test_content = models.CharField(max_length=50,default='male') # 字元型別的欄位 設定最大長度與預設值
# 如果不指定表名,django預設表明是 'appname_classname'
class Meta:
'''
使用如下語句定義表名
db_table = 'test_model'
'''
def __unicode__(self):
return '%d: %s' % (self.pk, self.test_name)
- 開啟 CMD 鍵入 如下命令:
python36 manage.py makemigrations #不指定app將遷移全部資料
python36 manage.py makemigrations test_app # 可以選擇單個app進行資料遷移
#以上兩個都可以,在app多的時候,建議使用下面的單個遷移
#該命令只是生成遷移檔案,並沒有真正的操作資料庫
#######################################################################################
#返回如下結果
Migrations for 'test_app':
test_app\migrations\0001_initial.py
- Create model TestModel
- 下面我檢視資料夾 test_project\test_app\migrations 增加了檔案 0001_initial.py,第一次遷移檔名應該都是這個,之後會不同。檢視 檔案 0001_initial.py 內容如下:
# Generated by Django 2.0 on 2018-11-15 03:00
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='TestModel',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('test_name', models.CharField(default='no_name', max_length=100)),
('test_content', models.CharField(default='male', max_length=50)),
],
),
]
# 我們可以看到,錢 Migration類中,定義了新的 模型 TestModel,並且有三個欄位 id、test_name、test_content
- 我每次遷移的時候都會檢視,生成的遷移檔案,確保都是我想要的資料庫改動。開啟CMD 鍵入指令:
python36 manage.py migrate
#該指令將,真正將建表操作到mysql資料庫中
#######################################################################################
#會看到如下提示
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions, test_app
Running migrations:
Applying test_app.0001_initial... OK
#可以發現執行了 剛才的 0001_initial.py 檔案中的內容
- 我們開啟mysql 資料庫檢視,是否存在表
mysql> show create table test_app_testmodel
-> ;
+--------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+--------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| test_app_testmodel | CREATE TABLE `test_app_testmodel` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`test_name` varchar(100) NOT NULL,
`test_content` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+--------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
- 至此,模型與資料庫已經實現了同步。
使用 django admin管理資料庫資料
- 之前說過 test_app下的檔案 admin.py 新增如下內容:
from django.contrib import admin
from .models import TestModel
# Register your models here.
@admin.register(TestModel)
class TestModelAdmin(admin.ModelAdmin):
list_display = ('pk', 'test_name') #在後臺列表下顯示的欄位
進入 django admin頁面 輸入超級使用者使用者名稱、密碼
通過 admin 管理 test model,點選上面的 Test models 可以通過頁面進行增、刪、改、查的操作
介紹一下Django提供的欄位型別
- 基本型別
AutoField #自增列,如果不存在的話會新增一個自增的ID列
BigAutoField # 64位的,比上面自增列大
BigIntegerField #64 位的整型
BinaryField #原生的二進位制列
BooleanField#布林
CharField#字串,注意該欄位必須指定 max_length
DateField#日期,可以指定auto_now 與 auto_now_add可以自動填充當前列為當前時間
DateTimeField# datetime
DecimalField# 小數點
DurationField# 與python的timedelta對應
EmailField
FileField
FileField and FieldFile
FilePathField
FloatField
ImageField
IntegerField
GenericIPAddressField
NullBooleanField
PositiveIntegerField
PositiveSmallIntegerField
SlugField
SmallIntegerField
TextField
TimeField
URLField
UUIDField
# 不是所有的 field 都用過,有興趣請自行嘗試
- ArrayField
最近使用 Postgresql 開發,發現它支援,array型別。在Django,中同樣支援,程式碼如下:
class TestModel(models.Model):
test_array = ArrayField(models.CharField(max_length=96, null=False, default=''), default="{}", size="99")
# 意思為增加一個 test_array陣列欄位,並且陣列元素都是char ,可以更換成其他型別
#此處default {}是因為 postgresql在檢測的時候強制插入資料為 '{a,b,c,d}',default空的話會報錯
class Meta:
db_table = 'test_model'
def __str__(self):
return self.node
程式碼中的增刪改查
- 分別在以下檔案中新增如下程式碼,路由具體說明將會重新寫一篇文章
# test_project/test_project/urls.py
from django.conf.urls import url
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
url(r'^admin/', admin.site.urls),
path('', include('test_app.urls')),#包括test_app的url
]
#建立 test_project/test_app/urls.py
from django.conf.urls import url
from test_app import views
urlpatterns = [
url('test_app/test_model', views.test_model),
]
- 查
# 需要定義一個查詢的api
# test_project/test_app/views.py
from django.shortcuts import render
from django.http import HttpResponse
from . import models
import json as json
from django.core import serializers
def test_model(request):
data = models.TestModel.objects.all()
data_json = json.loads(serializers.serialize('json', data))#將queryset變成json輸出
print(str(data_json))
return HttpResponse(data_json);
#啟動Django服務後,在瀏覽器中輸入 localhost:8000/test_app/test_model
#列印結果將在cmd顯示
# 更換不同的查詢方式,列印輸出結果
# 資料庫中插入了兩條資料
models.TestModel.objects.all() #獲取所有的資料 返回queryset
models.TestModel.objects.all().values('test_name') #只取test_name列 返回queryset
models.TestModel.objects.get("id=1") #只要id=1 返回object
models.TestModel.objects.all().filter("id=2") #只要id=2 返回queryset
models.TestModel.objects.all().exclude("id=2") #排除id=2 返回queryset
#列印結果
*******
[{'model': 'test_app.testmodel', 'pk': 1, 'fields': {'test_name': 'name1', 'test_content': 'content1'}}, {'model': 'test_app.testmodel', 'pk': 2, 'fields': {'test_name': 'test2', 'test_content': 'content2'}}]
*******
<QuerySet [{'test_name': 'name1'}, {'test_name': 'test2'}]>
*******
TestModel object (1)
*******
[{'model': 'test_app.testmodel', 'pk': 2, 'fields': {'test_name': 'test2', 'test_content': 'content2'}}]
*******
<QuerySet [<TestModel: TestModel object (1)>]>
*******
#更細節的查詢,官網檢視吧
https://docs.djangoproject.com/en/2.0/topics/db/queries/
- 增
#更改 test_project/test_app/urls.py,新增對於增加資料的url配置
from django.conf.urls import url
from test_app import views
urlpatterns = [
url('test_app/test_model', views.test_model),
# new add
url('test_app/test_addto_model', views.add_test_model),
]
#更改 test_project/test_app/views.py 新增如下函式程式碼
def add_test_model(request):
models.TestModel.objects.create(
test_name="name_add_by_code",test_content="content_add")
new_data = models.TestModel.objects.all()
new_data_json = json.loads(serializers.serialize('json', new_data))
return HttpResponse(new_data_json);
#啟動 django 服務後,訪問連結 localhost:8000/test_app/test_addto_model
頁面輸入結果:
{'model': 'test_app.testmodel', 'pk': 1, 'fields': {'test_name': 'name1', 'test_content': 'content1'}}{'model': 'test_app.testmodel', 'pk': 2, 'fields': {'test_name': 'test2', 'test_content': 'content2'}}{'model': 'test_app.testmodel', 'pk': 3, 'fields': {'test_name': 'name_add_by_code', 'test_content': 'content_add'}}
資料庫查詢結果
mysql> select * from test_app_testmodel;
+----+------------------+--------------+
| id | test_name | test_content |
+----+------------------+--------------+
| 1 | name1 | content1 |
| 2 | test2 | content2 |
| 3 | name_add_by_code | content_add |
+----+------------------+--------------+
3 rows in set (0.00 sec)
增加成功
# 由於考慮到資料完整行,簡單介紹一下 Django 的 【事物】
from django.db import transaction
with transaction.atomic():
#資料庫操作
#上面是最簡單的方法,過程中報錯將不會操作資料庫
#詳情參加官網:https://docs.djangoproject.com/en/2.0/topics/db/transactions/
- 改
#不做演示了,直接上程式碼
models.UserInfo.objects.filter(test_name='nam1').update(test_content='content1_update')
- 刪
#刪除的時候一定要filter一下呦
models.UserInfo.objects.filter(test_name='test2').delete()
資料庫結構的匯入到程式碼
- 下載了專案程式碼,但是本地資料庫中沒有專案表結構
- 資料庫在後臺改動了,要同步到程式碼中
python36 manage.py inspectdb
注:在使用makemigrations 與 migrate時,每一次的 makemigrations 是基於上一個makemigrations進行比較的,如果某一次的makemigrations後,migrate失敗,切記到 app下 migrations資料夾下刪除,最新的makemigrations檔案,然後修改model程式碼,重新makemigrations,否則將會報錯一直遷移不到資料庫中。被這個坑了好久。