42
mysql的安裝
navicat安裝
mysql驅(qū)動(dòng)程序安裝 mysqlclient 、pymysql
43
44
45
46 ORM模型
ORM模型介紹:
隨著項(xiàng)目越來越大昧旨,采用寫原生SQL的方式在代碼中會出現(xiàn)大量的SQL語句拾给,那么問題就出現(xiàn)了:
1、SQL語句重復(fù)利用率不高兔沃,越復(fù)雜的SQL語句條件越多蒋得,代碼越長。會出現(xiàn)很多相近的SQL語句乒疏;
2额衙、很多SQL語句是在業(yè)務(wù)邏輯中拼出來的,如果有數(shù)據(jù)庫需要更改,就要去修改這些邏輯窍侧,這會很容易漏掉對某些SQL語句的修改追驴;
3、寫SQL時(shí)容易忽略web安全問題,給給未來造成隱患。SQL注入耙旦;
如何解決上面的問題:
ORM 榕暇,全稱 Object Relational Mapping ,中文叫做對象關(guān)系映射抒和,通過 ORM 我們可以通過類的方式去操作數(shù)據(jù)庫,而不用再寫原生的SQL語句。通過把表映射成類亏镰,把行作實(shí)例,把字段作為屬性拯爽, ORM 在執(zhí)行對象操作的時(shí)候最終還是會把對應(yīng)的操作轉(zhuǎn)換為數(shù)據(jù)庫原生語句索抓。使用 ORM 有許多優(yōu)點(diǎn):
1、易用性:使用 ORM 做數(shù)據(jù)庫的開發(fā)可以有效的減少重復(fù)SQL語句的概率毯炮,寫出來的模型也更加直觀逼肯、清晰;
2桃煎、性能損耗欣捍薄: ORM 轉(zhuǎn)換成底層數(shù)據(jù)庫操作指令確實(shí)會有一些開銷。但從實(shí)際的情況來看为迈,這種性能損耗很少(不足5%)三椿,只要不是對性能有嚴(yán)苛的要求,綜合考慮開發(fā)效率葫辐、代碼的閱讀性搜锰,帶來的好處要遠(yuǎn)遠(yuǎn)大于性能損耗,而且項(xiàng)目越大作用越明顯耿战;
3蛋叼、設(shè)計(jì)靈活:可以輕松的寫出復(fù)雜的查詢;
4昆箕、可移植性: Django 封裝了底層的數(shù)據(jù)庫實(shí)現(xiàn)鸦列,支持多個(gè)關(guān)系數(shù)據(jù)庫引擎,包括流行的 MySQL 鹏倘、 PostgreSQL 和 SQLite 薯嗤。可以非常輕松的切換數(shù)據(jù)庫纤泵;
47創(chuàng)建和映射ORM模型
ORM 模型一般都是放在app的models.py文件中骆姐。每個(gè)app都可以擁有自己的模型镜粤,并且如果這個(gè)模型想要映射到數(shù)據(jù)庫中,那么這個(gè) app 必須要放在項(xiàng)目的settings.py文件的INSTALLED_APP 中進(jìn)行安裝玻褪。
示例代碼如下:
from django.db import models
如果要將一個(gè)普通的類變成一個(gè)可以映射到數(shù)據(jù)庫中的ORM模型
那么必須要將父類設(shè)置為models.Model或者他的子類
class Book(models.Model):
# 1. id:int類型肉渴,是自增長的。
id = models.AutoField(primary_key=True)
# 2. name:varchar(100)带射,圖書的名字
name = models.CharField(max_length=100,null=False)
# 3. author:varchar(100)同规,圖書的作者
author = models.CharField(max_length=100,null=False)
# 4. price:float,圖書的價(jià)格
price = models.FloatField(null=False,default=0)
class Publisher(models.Model):
name = models.CharField(max_length=100,null=False)
address = models.CharField(max_length=100,null=False)
使用makemigrations生成遷移腳本文件
python manage.py makemigrations使用migrate將新生成的遷移腳本文件映射到數(shù)據(jù)庫中
python manage.py migrate
將 ORM 模型映射到數(shù)據(jù)庫中窟社,總結(jié)起來就是以下幾步:
總結(jié)
1券勺、在 settings.py 中,配置好 DATABASES 灿里,做好數(shù)據(jù)庫相關(guān)的配置关炼;
2、在 app 中的 models.py 中定義好模型匣吊,這個(gè)模型必須繼承自 django.db.models 儒拂;
3、將這個(gè) app 添加到 settings.py 的 INSTALLED_APP 中色鸳;
4社痛、在命令行終端,進(jìn)入到項(xiàng)目所在的路徑缕碎,然后執(zhí)行命令:python manage.py makemigrations 來生成遷移腳本文件褥影。
5、同樣在命令行中咏雌,執(zhí)行命令 python manage.py migrate 來將遷移腳本文件映射到數(shù)據(jù)庫中;
48 ORM對數(shù)據(jù)庫的基本操作:
添加數(shù)據(jù):
只要使用ORM模型創(chuàng)建一個(gè)對象校焦。然后再調(diào)用這個(gè)ORM模型的save
方法就可以保存了赊抖。
示例代碼如下:
book = Book(name='西游記',author='吳承恩',price=100)
book.save()
查找數(shù)據(jù):
所有的查找工作都是使用模型上的objects
屬性來完成的。當(dāng)然也可以自定義查詢對象寨典。這部分功能會在后面講到氛雪。
- 根據(jù)主鍵進(jìn)行查找:使用主鍵進(jìn)行查找∷食桑可以使用
objects.get
方法报亩。然后傳遞pk=xx
的方式進(jìn)行查找。示例代碼如下:book = Book.objects.get(pk=2)
- 根據(jù)其他字段進(jìn)行查找:可以使用
objects.filter
方法進(jìn)行查找井氢。示例代碼如下:
使用books = Book.objects.filter(name='三國演義')
filter
方法返回來的是一個(gè)QuerySet
對象弦追。這個(gè)對象類似于列表。我們可以使用這個(gè)對象的first
方法來獲取第一個(gè)值花竞。
刪除數(shù)據(jù):
首先查找到對應(yīng)的數(shù)據(jù)模型劲件。然后再執(zhí)行這個(gè)模型的delete
方法即可刪除。示例代碼如下:
book = Book.objects.get(pk=1)
book.delete()
修改數(shù)據(jù):
首先查找到對應(yīng)的數(shù)據(jù)模型。然后修改這個(gè)模型上的屬性的值零远。再執(zhí)行save
方法即可修改完成苗分。示例代碼如下:
book = Book.objects.get(pk=2)
book.price = 200
book.save()
49 常用Field
AutoField
自增長
BigAutoField
范圍更大的
BooleanField
true/false
CharField
小于254的字符使用這個(gè)
50 關(guān)于時(shí)間的我Field
navie時(shí)間和aware時(shí)間:
什么是navie時(shí)間?什么是aware時(shí)間牵辣?
- navie時(shí)間:不知道自己的時(shí)間表示的是哪個(gè)時(shí)區(qū)的摔癣。也就是不知道自己幾斤幾兩。比較幼稚纬向。
- aware時(shí)間:知道自己的時(shí)間表示的是哪個(gè)時(shí)區(qū)的择浊。也就是比較清醒。
pytz庫:
專門用來處理時(shí)區(qū)的庫罢猪。這個(gè)庫會經(jīng)常更新一些時(shí)區(qū)的數(shù)據(jù)近她,不需要我們擔(dān)心。并且這個(gè)庫在安裝Django的時(shí)候會默認(rèn)的安裝膳帕。如果沒有安裝粘捎,那么可以通過pip install pytz
的方式進(jìn)行安裝。
astimezone方法:
將一個(gè)時(shí)區(qū)的時(shí)間轉(zhuǎn)換為另外一個(gè)時(shí)區(qū)的時(shí)間危彩。這個(gè)方法只能被aware
類型的時(shí)間調(diào)用攒磨。不能被navie
類型的時(shí)間調(diào)用。
示例代碼如下:
import pytz
from datetime import datetime
now = datetime.now() # 這是一個(gè)navie類型的時(shí)間
utc_timezone = pytz.timezone("UTC") # 定義UTC的時(shí)區(qū)對象
utc_now = now.astimezone(utc_timezone) # 將當(dāng)前的時(shí)間轉(zhuǎn)換為UTC時(shí)區(qū)的時(shí)間
>> ValueError: astimezone() cannot be applied to a naive datetime # 會拋出一個(gè)異常汤徽,原因就是因?yàn)閚avie類型的時(shí)間不能調(diào)用astimezone方法
now = now.replace(tzinfo=pytz.timezone('Asia/Shanghai'))
utc_now = now.astimezone(utc_timezone)
# 這時(shí)候就可以正確的轉(zhuǎn)換娩缰。
replace方法:
可以將一個(gè)時(shí)間的某些屬性進(jìn)行更改。
51#
django.utils.timezone.now方法:
會根據(jù)settings.py
中是否設(shè)置了USE_TZ=True
獲取當(dāng)前的時(shí)間谒府。如果設(shè)置了拼坎,那么就獲取一個(gè)aware
類型的UTC
時(shí)間。如果沒有設(shè)置完疫,那么就會獲取一個(gè)navie
類型的時(shí)間泰鸡。
django.utils.timezone.localtime方法:
會根據(jù)setting.py
中的TIME_ZONE
來將一個(gè)aware
類型的時(shí)間轉(zhuǎn)換為TIME_ZONE
指定時(shí)區(qū)的時(shí)間。
DateField:
日期類型壳鹤。在Python
中是datetime.date
類型盛龄,可以記錄年月日。在映射到數(shù)據(jù)庫中也是date
類型芳誓。使用這個(gè)Field
可以傳遞以下幾個(gè)參數(shù):
-
auto_now
:在每次這個(gè)數(shù)據(jù)保存的時(shí)候余舶,都使用當(dāng)前的時(shí)間。比如作為一個(gè)記錄修改日期的字段锹淌,可以將這個(gè)屬性設(shè)置為True
匿值。 -
auto_now_add
:在每次數(shù)據(jù)第一次被添加進(jìn)去的時(shí)候,都使用當(dāng)前的時(shí)間葛圃。比如作為一個(gè)記錄第一次入庫的字段千扔,可以將這個(gè)屬性設(shè)置為True
憎妙。
DateTimeField:
日期時(shí)間類型再沧,類似于DateField
杨拐。不僅僅可以存儲日期,還可以存儲時(shí)間鹃操。映射到數(shù)據(jù)庫中是datetime
類型龙誊。這個(gè)Field
也可以使用auto_now
和auto_now_add
兩個(gè)屬性抚垃。
TimeField:
時(shí)間類型。在數(shù)據(jù)庫中是time
類型趟大。在Python
中是datetime.time
類型鹤树。
navie和aware介紹以及在django中的用法:
https://docs.djangoproject.com/en/2.0/topics/i18n/timezones/
52
EmailField:
類似于CharField
。在數(shù)據(jù)庫底層也是一個(gè)varchar
類型逊朽。最大長度是254個(gè)字符罕伯。
FileField:
用來存儲文件的。這個(gè)請參考后面的文件上傳章節(jié)部分叽讳。
ImageField:
用來存儲圖片文件的追他。這個(gè)請參考后面的圖片上傳章節(jié)部分。
FloatField:
浮點(diǎn)類型岛蚤。映射到數(shù)據(jù)庫中是float
類型邑狸。
IntegerField:
整形。值的區(qū)間是-2147483648——2147483647
涤妒。
BigIntegerField:
大整形单雾。值的區(qū)間是-9223372036854775808——9223372036854775807
。
PositiveIntegerField:
正整形她紫。值的區(qū)間是0——2147483647
硅堆。
SmallIntegerField:
小整形。值的區(qū)間是-32768——32767
贿讹。
PositiveSmallIntegerField:
正小整形硬萍。值的區(qū)間是0——32767
。
TextField:
大量的文本類型围详。映射到數(shù)據(jù)庫中是longtext類型。
UUIDField:
只能存儲uuid
格式的字符串祖屏。uuid
是一個(gè)32位的全球唯一的字符串助赞,一般用來作為主鍵。
URLField:
類似于CharField
袁勺,只不過只能用來存儲url
格式的字符串雹食。并且默認(rèn)的max_length
是200。
53
Field常用的參數(shù)
null:
如果設(shè)置為True
期丰,Django
將會在映射表的時(shí)候指定是否為空群叶。默認(rèn)是為False
吃挑。在使用字符串相關(guān)的Field
(CharField/TextField)的時(shí)候,官方推薦盡量不要使用這個(gè)參數(shù)街立,也就是保持默認(rèn)值False
舶衬。因?yàn)?code>Django在處理字符串相關(guān)的Field
的時(shí)候,即使這個(gè)Field
的null=False
赎离,如果你沒有給這個(gè)Field
傳遞任何值逛犹,那么Django
也會使用一個(gè)空的字符串""
來作為默認(rèn)值存儲進(jìn)去。因此如果再使用null=True
梁剔,Django
會產(chǎn)生兩種空值的情形(NULL或者空字符串)虽画。如果想要在表單驗(yàn)證的時(shí)候允許這個(gè)字符串為空,那么建議使用blank=True
荣病。如果你的Field
是BooleanField
码撰,那么對應(yīng)的可空的字段則為NullBooleanField
。
blank:
標(biāo)識這個(gè)字段在表單驗(yàn)證的時(shí)候是否可以為空个盆。默認(rèn)是False
脖岛。
這個(gè)和null
是有區(qū)別的,null
是一個(gè)純數(shù)據(jù)庫級別的砾省。而blank
是表單驗(yàn)證級別的鸡岗。
db_column:
這個(gè)字段在數(shù)據(jù)庫中的名字。如果沒有設(shè)置這個(gè)參數(shù)编兄,那么將會使用模型中屬性的名字轩性。
default:
默認(rèn)值『菰В可以為一個(gè)值揣苏,或者是一個(gè)函數(shù),但是不支持lambda
表達(dá)式件舵。并且不支持列表/字典/集合等可變的數(shù)據(jù)結(jié)構(gòu)卸察。
primary_key:
是否為主鍵。默認(rèn)是False
铅祸。
unique:
在表中這個(gè)字段的值是否唯一坑质。一般是設(shè)置手機(jī)號碼/郵箱等。
更多Field
參數(shù)請參考官方文檔:https://docs.djangoproject.com/zh-hans/2.0/ref/models/fields/
54
模型中Meta
配置:
對于一些模型級別的配置临梗。我們可以在模型中定義一個(gè)類涡扼,叫做Meta
。然后在這個(gè)類中添加一些類屬性來控制模型的作用盟庞。比如我們想要在數(shù)據(jù)庫映射的時(shí)候使用自己指定的表名吃沪,而不是使用模型的名稱。那么我們可以在Meta
類中添加一個(gè)db_table
的屬性什猖。示例代碼如下:
class Book(models.Model):
name = models.CharField(max_length=20,null=False)
desc = models.CharField(max_length=100,name='description',db_column="description1")
class Meta:
db_table = 'book_model'
以下將對Meta
類中的一些常用配置進(jìn)行解釋票彪。
db_table:
這個(gè)模型映射到數(shù)據(jù)庫中的表名红淡。如果沒有指定這個(gè)參數(shù),那么在映射的時(shí)候?qū)褂媚P兔麃碜鳛槟J(rèn)的表名降铸。
ordering:
設(shè)置在提取數(shù)據(jù)的排序方式在旱。后面章節(jié)會講到如何查找數(shù)據(jù)。比如我想在查找數(shù)據(jù)的時(shí)候根據(jù)添加的時(shí)間排序垮耳,那么示例代碼如下:
class Book(models.Model):
name = models.CharField(max_length=20,null=False)
desc = models.CharField(max_length=100,name='description',db_column="description1")
pub_date = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'book_model'
ordering = ['pub_date']
更多的配置后面會慢慢介紹到颈渊。
官方文檔:https://docs.djangoproject.com/en/2.0/ref/models/options/
55 #56 ORM外鍵
了解外鍵
在MySQL中,表有兩種引擎终佛,一種是InnoDB俊嗽,另外一種是myisam。如果使用的是InnoDB引擎铃彰,是支持外鍵約束的绍豁。外鍵的存在使得ORM框架在處理表關(guān)系的時(shí)候異常的強(qiáng)大。MySQL數(shù)據(jù)庫默認(rèn)使用的也是InnoDB引擎牙捉。
使用外鍵
新建一個(gè)項(xiàng)目竹揍,創(chuàng)建一個(gè)article的app,添加至settings中邪铲,并且在settings中設(shè)置數(shù)據(jù)庫的連接芬位,調(diào)至整個(gè)項(xiàng)目能運(yùn)行為止。
類定義為class ForeignKey(to,on_delete,**options)带到。第一個(gè)參數(shù)是引用的是哪個(gè)模型昧碉,第二個(gè)參數(shù)是在使用外鍵引用的模型數(shù)據(jù)被刪除了,這個(gè)字段該如何處理揽惹,比如有CASCADE被饿、SET_NULL等(外鍵刪除各個(gè)參數(shù)的意思)。這里以一個(gè)實(shí)際案例來說明搪搏。比如有一個(gè)Category和一個(gè)Article兩個(gè)模型狭握。一個(gè)種類下可以包含多篇文章,一個(gè)Article只能有一個(gè)種類疯溺,并且通過外鍵進(jìn)行引用论颅。那么相關(guān)的示例代碼如下:
- 在同一個(gè)app中使用外鍵
在article中的models中寫入代碼:
from django.db import models
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=100)
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
# 是由Category影響Article
category = models.ForeignKey('Category',on_delete=models.CASCADE)
這里我們就在Article中設(shè)置了一個(gè)外鍵category。
以上使用ForeignKey來定義模型之間的關(guān)系囱嫩。即在article的實(shí)例中可以通過category屬性來操作對應(yīng)的Category模型嗅辣。這樣使用起來非常的方便。示例代碼如下:views中寫入
from django.shortcuts import render
from . import models
from django.http import HttpResponse
# Create your views here.
def index(request):
# 插入數(shù)據(jù)
# article = models.Article(title='abc',content='111')
# category = models.Category(name='最新文章')
# category.save()
# article.category = category
# article.save()
#讀取數(shù)據(jù)
article = models.Article.objects.first()
print(article.category.name)
return HttpResponse('successful')
在上面代碼中把相應(yīng)的注釋去了挠说,就能夠進(jìn)行測試了。
為什么使用了ForeignKey后愿题,就能通過category訪問到對應(yīng)的Catrgory對象呢损俭。因此在底層蛙奖,Django為Article表添加了一個(gè)屬性名_id的字段(比如category的字段名稱是category_id),這個(gè)字段是一個(gè)外鍵杆兵,記錄著對應(yīng)的種類的主鍵雁仲。以后通過article.category訪問的時(shí)候,實(shí)際上是先通過category_id找到對應(yīng)的數(shù)據(jù)见间,然后再提取Category表中的這條數(shù)據(jù)礼饱,形成一個(gè)模型继蜡。
如果想要引用另外一個(gè)app的模型,那么應(yīng)該在傳遞to參數(shù)的時(shí)候吹艇,使用app.model_name進(jìn)行指定。例如昂拂,如果User和Article不是在同一個(gè)app中受神,那么在引用的時(shí)候的示例代碼如下:
首先新建一個(gè)user的app,并且添加至settings中格侯,在user中的models中寫入代碼鼻听,創(chuàng)建一個(gè)User模型
from django.db import models
# Create your models here.
class User(models.Model):
username = models.CharField(max_length=100)
再在article中的models中添加這個(gè)外鍵,即在Article這個(gè)模型中新添加一個(gè)屬性
# 將user中的User這個(gè)模型作為外鍵
author = models.ForeignKey('user.User',on_delete=models.CASCADE,null=True)
如果模型的外鍵引用的是本身自己這個(gè)模型联四,那么to參數(shù)可以為self撑碴,或者是這個(gè)模型的名字。在論壇開發(fā)中朝墩,一般評論都可以進(jìn)行二級評論醉拓,即可以針對另外一個(gè)評論進(jìn)行評論,那么在定義模型的時(shí)候就需要使用外鍵來引用自身鱼辙。示例代碼如下:
class Comment(models.Model):
content = models.TextField()
orihin_comment = models.ForeignKey('self',on_delete=models.CASCADE)
這樣我們就實(shí)現(xiàn)了添加了一個(gè)外鍵引用自身廉嚼。
外間刪除操作的參數(shù)意思:
如果一個(gè)模型使用了外鍵。那么在對方那個(gè)模型被刪掉后倒戏,該進(jìn)行什么樣的操作怠噪。可以通過on_delete來指定杜跷“睿可以指定的類型如下:
CASCADE:級聯(lián)操作。如果外鍵對應(yīng)的那條數(shù)據(jù)被刪除了葛闷,那么這條數(shù)據(jù)也會被刪除憋槐。
PROTECT:受保護(hù)。即只要這條數(shù)據(jù)引用了外鍵的那條數(shù)據(jù)淑趾,那么就不能刪除外鍵的那條數(shù)據(jù)阳仔。如果我們強(qiáng)行刪除,Django就會報(bào)錯(cuò)扣泊。
SET_NULL:設(shè)置為空近范。如果外鍵的那條數(shù)據(jù)被刪除了嘶摊,那么在本條數(shù)據(jù)上就將這個(gè)字段設(shè)置為空。如果設(shè)置這個(gè)選項(xiàng)评矩,前提是要指定這個(gè)字段可以為空叶堆。
SET_DEFAULT:設(shè)置默認(rèn)值。如果外鍵的那條數(shù)據(jù)被刪除了斥杜,那么本條數(shù)據(jù)上就將這個(gè)字段設(shè)置為默認(rèn)值虱颗。如果設(shè)置這個(gè)選項(xiàng),== 前提是要指定這個(gè)字段一個(gè)默認(rèn)值 ==蔗喂。
SET():如果外鍵的那條數(shù)據(jù)被刪除了忘渔。那么將會獲取SET函數(shù)中的值來作為這個(gè)外鍵的值。SET函數(shù)可以接收一個(gè)可以調(diào)用的對象(比如函數(shù)或者方法)弱恒,如果是可以調(diào)用的對象辨萍,那么會將這個(gè)對象調(diào)用后的結(jié)果作為值返回回去。== 可以不用指定默認(rèn)值 ==
DO_NOTHING:不采取任何行為返弹。一切全看數(shù)據(jù)庫級別的約束锈玉。
以上這些選項(xiàng)只是Django級別的,數(shù)據(jù)級別依舊是RESTRICT义起!
數(shù)據(jù)庫層面的約束有四種:
RESTRICT:默認(rèn)的選項(xiàng)拉背,如果想要?jiǎng)h除父表的記錄時(shí),而在子表中有關(guān)聯(lián)該父表的記錄默终,則不允許刪除父表中的記錄椅棺;
NOACTION:同 RESTRICT效果一樣,也是首先先檢查外鍵;
CASCADE:父表delete齐蔽、update的時(shí)候两疚,子表會delete、update掉關(guān)聯(lián)記錄含滴;
SET NULL:父表delete诱渤、update的時(shí)候,子表會將關(guān)聯(lián)記錄的外鍵字段所在列設(shè)為null谈况,所以注意在設(shè)計(jì)子表時(shí)外鍵不能設(shè)為not null勺美;
參考鏈接:https://blog.csdn.net/yajing8/article/details/73014004
為什么ORM能越過數(shù)據(jù)庫的約束呢?
是因?yàn)镺RM操作是反過來的碑韵,比如我們在ORM模型中設(shè)置了on_delete=models.CASCADE赡茸,那么在進(jìn)行刪除的時(shí)候,如果發(fā)現(xiàn)在數(shù)據(jù)庫層面有父表約束著它祝闻,使他不能被刪除占卧,那么ORM就會先去刪除父表,再來刪除指定的表,從而達(dá)到越過了數(shù)據(jù)庫層面的約束屉栓。
57 表關(guān)系
一對多
- 應(yīng)用場景:比如文章和作者之間的關(guān)系舷蒲。一個(gè)文章只能由一個(gè)作者編寫,但是一個(gè)作者可以寫多篇文章友多。文章和作者之間的關(guān)系就是典型的多對一的關(guān)系。
- 實(shí)現(xiàn)方式:一對多或者多對一堤框,都是通過
ForeignKey
來實(shí)現(xiàn)的域滥。還是以文章和作者的案例進(jìn)行講解。
class User(models.Model):
username = models.CharField(max_length=20)
password = models.CharField(max_length=100)
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
author = models.ForeignKey("User",on_delete=models.CASCADE)
那么以后在給Article
對象指定author
蜈抓,就可以使用以下代碼來完成:
article = Article(title='abc',content='123')
author = User(username='zhiliao',password='111111')
# 要先保存到數(shù)據(jù)庫中
author.save()
article.author = author
article.save()
并且以后如果想要獲取某個(gè)用戶下所有的文章启绰,可以通過article_set
來實(shí)現(xiàn)。示例代碼如下:
user = User.objects.first()
# 獲取第一個(gè)用戶寫的所有文章
articles = user.article_set.all()
for article in articles:
print(article)
并且如果想要將文章添加到某個(gè)分類中沟使∥桑可以使用一下的方式:
category = Category.objects.first()
article = Article(title='bbb',content='vvv')
article.author = FrontUser.objects.first()
category.article_set.add(article,bulk=False)
- 使用
bulk=False
,那么Django會自動(dòng)的保存article腊嗡,而不需要在添加到category之前先保存article着倾。 - 或者是另外一種解決方式是,在添加到
category.article_set
中之前燕少,先將article
保存到數(shù)據(jù)庫中卡者。但是如果article.category
不能為空,那么就產(chǎn)生一種死循環(huán)了崇决,article沒有category
不能保存,而將article添加到cateogry.artile_set
中底挫,又需要article之前是已經(jīng)存儲到數(shù)據(jù)庫中的恒傻。 - 如果是上面的那種需求,建議使用
bulk=False
的解決方案建邓。
58
一對一:
- 在Django中一對一是通過
models.OnetToOneField
來實(shí)現(xiàn)的盈厘。這個(gè)OneToOneField
其實(shí)本質(zhì)上就是一個(gè)外鍵,只不過這個(gè)外鍵有一個(gè)唯一約束(unique key)
涝缝,來實(shí)現(xiàn)一對一扑庞。 - 以后如果想要反向引用,那么是通過引用的模型的名字轉(zhuǎn)換為小寫的形式進(jìn)行訪問拒逮。比如以下模型:
class FrontUser(models.Model): username = models.CharField(max_length=200) class UserExtension(models.Model): school = models.CharField(max_length=100) user = models.OneToOneField("FrontUser",on_delete=models.CASCADE) # 通過userextension來訪問UserExtension對象 user = FrontUser.objects.first() print(user.userextension)
UserExtension
的對象罐氨,可以通過user
來訪問到對應(yīng)的user對象。并且FrontUser
對象可以使用userextension
來訪問對應(yīng)的UserExtension
對象滩援。
如果不想使用Django默認(rèn)的引用屬性名字栅隐。那么可以在OneToOneField
中添加一個(gè)related_name
參數(shù)。示例代碼如下:
那么以后就class FrontUser(models.Model): username = models.CharField(max_length=200) class UserExtension(models.Model): school = models.CharField(max_length=100) user = models.OneToOneField("FrontUser",on_delete=models.CASCADE,related_name='extension') # 通過extension來訪問到UserExtension對象 user = FrontUser.objects.first() print(user.extension)
FrontUser
的對象就可以通過extension
屬性來訪問到對應(yīng)的UserExtension
對象。
59
多對多:
應(yīng)用場景:比如文章和標(biāo)簽的關(guān)系租悄。一篇文章可以有多個(gè)標(biāo)簽谨究,一個(gè)標(biāo)簽可以被多個(gè)文章所引用。因此標(biāo)簽和文章的關(guān)系是典型的多對多的關(guān)系泣棋。
實(shí)現(xiàn)方式:
Django
為這種多對多的實(shí)現(xiàn)提供了專門的Field
胶哲。叫做ManyToManyField
。還是拿文章和標(biāo)簽為例進(jìn)行講解潭辈。示例代碼如下:
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
tags = models.ManyToManyField("Tag",related_name="articles")
class Tag(models.Model):
name = models.CharField(max_length=50)
在數(shù)據(jù)庫層面鸯屿,實(shí)際上Django
是為這種多對多的關(guān)系建立了一個(gè)中間表。這個(gè)中間表分別定義了兩個(gè)外鍵把敢,引用到article
和tag
兩張表的主鍵寄摆。
60ORM查詢條件詳解-準(zhǔn)備工作
61 pycharm連接數(shù)據(jù)庫
62 查詢操作
查找是數(shù)據(jù)庫操作中一個(gè)非常重要的技術(shù)。查詢一般就是使用filter修赞、exclude以及get三個(gè)方法來實(shí)現(xiàn)婶恼。我們可以在調(diào)用這些方法的時(shí)候傳遞不同的參數(shù)來實(shí)現(xiàn)查詢需求。在ORM層面柏副,這些查詢條件都是使用field+__+condition的方式來使用的勾邦。以下將那些常用的查詢條件來一一解釋。
exact:在底層會被翻譯成
=
。-
iexact:在底層會被翻譯成
LIKE
。- LIKE和=:大部分情況下都是等價(jià)的又跛,只有少數(shù)情況下是不等價(jià)的址否。
- exict和iexact:他們的區(qū)別其實(shí)就是LIKE和=的區(qū)別,因?yàn)閑xact會被翻譯成=,而iexact會被翻譯成LIKE。
- 因?yàn)?code>field__exact=xxx其實(shí)等價(jià)于
filed=xxx
,因此我們直接使用filed=xxx
就可以了椎椰,并且因?yàn)榇蟛糠智闆rexact
和iexact
又是等價(jià)的,因此我們以后直接使用field=xxx
就可以了沾鳄。
63
QuerySet.query:
query
可以用來查看這個(gè)ORM
查詢語句最終被翻譯成的SQL
語句慨飘。但是query
只能被用在QuerySet
對象上,不能用在普通的ORM模型
上译荞。因此如果你的查詢語句是通過get
來獲取數(shù)據(jù)的瓤的,那么就不能使用query
,因?yàn)?code>get返回的是滿足條件的ORM
模型吞歼,而不是QuerySet
圈膏。如果你是通過filter
等其他返回QuerySet
的方法查詢的,那么就可以使用query
篙骡。contains:使用大小寫敏感的判斷稽坤,某個(gè)字符串是否在指定的字段中丈甸。這個(gè)判斷條件會使用大小敏感,因此在被翻譯成
SQL
語句的時(shí)候尿褪,會使用like binary
睦擂,而like binary
就是使用大小寫敏感的。icontains:使用大小寫不敏感的判斷杖玲,某個(gè)字符串是否被包含在指定的字段中顿仇。這個(gè)查詢語句在被翻譯成
SQL
的時(shí)候,使用的是like
摆马,而like
在MySQL
層面就是不區(qū)分大小寫的夺欲。contains和icontains:在被翻譯成
SQL
的時(shí)候使用的是%hello%
,就是只要整個(gè)字符串中出現(xiàn)了hello
都能過夠被找到今膊,而iexact
沒有百分號,那么意味著只有完全相等的時(shí)候才會被匹配到伞剑。
64
-
in:可以直接指定某個(gè)字段的是否在某個(gè)集合中。示例代碼如下:
articles = Article.objects.filter(id__in=[1,2,3])
也可以通過其他的表的字段來判斷是否在某個(gè)集合中黎泣。示例代碼如下:
categories = Category.objects.filter(article__id__in=[1,2,3])
如果要判斷相關(guān)聯(lián)的表的字段恕刘,那么也是通過
__
來連接。并且在做關(guān)聯(lián)查詢的時(shí)候抒倚,不需要寫models_set
褐着,直接使用模型的名字的小寫化
就可以了。比如通過分類去查找相應(yīng)的文章托呕,那么通過article__id__in
就可以了含蓉,而不是寫成article_set__id__in
的形式。當(dāng)然如果你不想使用默認(rèn)的形式项郊,可以在外鍵定義的時(shí)候傳遞related_query_name
來指定反向查詢的名字馅扣。示例代碼如下:class Category(models.Model): name = models.CharField(max_length=100) class Meta: db_table = 'category' class Article(models.Model): title = models.CharField(max_length=200) content = models.TextField() cateogry = models.ForeignKey("Category",on_delete=models.CASCADE,null=True,related_query_name='articles') class Meta: db_table = 'article'
因?yàn)樵?code>cateogry的
ForeignKey
中指定了related_query_name
為articles
,因此你不能再使用article
來進(jìn)行反向查詢了着降。這時(shí)候就需要通過articles__id__in
來進(jìn)行反向查詢差油。反向查詢是將模型名字小寫化。比如
article__in
任洞⌒罾可以通過related_query_name
來指定自己的方式,而不使用默認(rèn)的方式交掏。
反向引用是將模型名字小寫化妆偏,然后再加上_set
,比如article_set
耀销,可以通過related_name
來指定自己的方式楼眷,而不是用默認(rèn)的方式铲汪。并且,如果在做反向查詢的時(shí)候罐柳,如果查詢的字段就是模型的主鍵掌腰,那么可以省略掉這個(gè)字段,直接寫成
article__in
就可以了张吉,不需要這個(gè)id
了齿梁。in
不僅僅可以指定列表/元組,還可以為QuerySet
肮蛹。比如要查詢“文章標(biāo)題中包含有hello的所有分類”勺择,那么可以通過以下代碼來實(shí)現(xiàn):articles = Article.objects.filter(title__icontains='hello') categories = Category.objects.filter(articles__in=articles) for cateogry in categories: print(cateogry)
65
- gt、gte伦忠、lt省核、lte:代表的是大于、大于等于昆码、小于气忠、小于等于的條件。示例代碼如下:
articles = Article.objects.filter(id__lte=3)
66
- startswith赋咽、istartswith旧噪、endswith、iendswith:表示以某個(gè)值開始脓匿,不區(qū)分大小寫的以某個(gè)值開始淘钟、以某個(gè)值結(jié)束、不區(qū)分大小寫的以某個(gè)值結(jié)束陪毡。示例代碼如下:
articles = Article.objects.filter(title__endswith="hello")
67
- 關(guān)于時(shí)間的查詢條件:
- range:可以指定一個(gè)時(shí)間段米母。并且時(shí)間應(yīng)該標(biāo)記為
aware
時(shí)間,不然django會報(bào)警告缤骨。示例代碼如下:start_time = make_aware(datetime(year=2018,month=4,day=4,hour=17,minute=0,second=0)) end_time = make_aware(datetime(year=2018,month=4,day=4,hour=18,minute=0,second=0)) articles = Article.objects.filter(create_time__range=(start_time,end_time)) print(articles.query) print(articles)
- range:可以指定一個(gè)時(shí)間段米母。并且時(shí)間應(yīng)該標(biāo)記為
68
- date:用年月日來進(jìn)行過濾爱咬。如果想要使用這個(gè)過濾條件,那么前提必須要在
MySQL
中添加好那些時(shí)區(qū)文件绊起。如何添加呢精拟?參考教案。示例代碼如下:articles = Article.objects.filter(create_time__date=datetime(year=2018,month=4,day=4))
- year/month/day:表示根據(jù)年/月/日進(jìn)行查找虱歪。示例代碼如下:
articles = Article.objects.filter(create_time__year__gte=2018)
- week_day:根據(jù)星期來進(jìn)行查找蜂绎。1表示星期天,7表示星期六笋鄙,2-6代表的是星期一到星期五师枣。比如要查找星期三的所有文章,那么可以通過以下代碼來實(shí)現(xiàn):
articles = Article.objects.filter(create_time__week_day=4)
- time:根據(jù)分時(shí)秒來進(jìn)行查找萧落。如果要具體到秒践美,一般比較難匹配到洗贰,可以使用區(qū)間的方式來進(jìn)行查找。區(qū)間使用
range
條件陨倡。比如想要獲取17時(shí)/10分/27-28秒之間的文章敛滋,那么可以通過以下代碼來實(shí)現(xiàn):start_time = time(hour=17,minute=10,second=27) end_time = time(hour=17,minute=10,second=28) articles = Article.objects.filter(create_time__time__range=(start_time,end_time))
69
isnull和regex
70聚合函數(shù)準(zhǔn)備
71
- 所有的聚合函數(shù)都是放在
django.db.models
下面。 - 聚合函數(shù)不能夠單獨(dú)的執(zhí)行兴革,需要放在一些可以執(zhí)行聚合函數(shù)的方法下面中去執(zhí)行绎晃。比如
aggregate
。示例代碼如下:result = Book.objects.aggregate(Avg("price"))
- 聚合函數(shù)執(zhí)行完成后杂曲,給這個(gè)聚合函數(shù)的值取個(gè)名字庶艾。取名字的規(guī)則,默認(rèn)是
filed+__+聚合函數(shù)名字
形成的擎勘。比如以上代碼形成的名字叫做price__avg
咱揍。如果不想使用默認(rèn)的名字,那么可以在使用聚合函數(shù)的時(shí)候傳遞關(guān)鍵字參數(shù)進(jìn)去棚饵,參數(shù)的名字就是聚合函數(shù)執(zhí)行完成的名字述召。實(shí)示例代碼如下:
以上傳遞了關(guān)鍵字參數(shù)result = Book.objects.aggregate(avg=Avg("price"))
avg=Avg("price")
,那么以后Avg
聚合函數(shù)執(zhí)行完成的名字就叫做avg
蟹地。 -
aggregate
:這個(gè)方法不會返回一個(gè)QuerySet
對象,而是返回一個(gè)字典藤为。這個(gè)字典中的key就是聚合函數(shù)的名字怪与,值就是聚合函數(shù)執(zhí)行后的結(jié)果。
72
-
aggregate
和annotate
的相同和不同:- 相同:這兩個(gè)方法都可以執(zhí)行聚合函數(shù)缅疟。
- 不同:
-
aggregate
返回的是一個(gè)字典分别,在這個(gè)字典中存儲的是這個(gè)聚合函數(shù)執(zhí)行的結(jié)果。而annotate
返回的是一個(gè)QuerySet
對象存淫,并且會在查找的模型上添加一個(gè)聚合函數(shù)的屬性耘斩。 -
aggregate
不會做分組,而annotate
會使用group by
子句進(jìn)行分組桅咆,只有調(diào)用了group by
子句括授,才能對每一條數(shù)據(jù)求聚合函數(shù)的值。
-
73
-
Count
:用來求某個(gè)數(shù)據(jù)的個(gè)數(shù)岩饼。比如要求所有圖書的數(shù)量荚虚,那么可以使用以下代碼:
并且result = Book.objects.aggregate(book_nums=Count("id"))
Count
可以傳遞distinct=True
參數(shù),用來剔除那些重復(fù)的值籍茧,只保留一個(gè)版述。比如要獲取作者表中,不同郵箱的個(gè)數(shù)寞冯,那么這時(shí)候可以使用distinct=True
渴析。示例代碼如下:result = Author.objects.aggregate(email_nums=Count('email',distinct=True))
74
-
Max
和Min
:求指定字段的最大值和最小值晚伙。示例代碼如下:result = Author.objects.aggregate(max=Max("age"),min=Min("age"))
75
-
Sum
:求某個(gè)字段值的總和恢恼。示例代碼如下:result = BookOrder.objects.aggregate(total=Sum('price'))
aggregate
和annotate
方法可以在任何的QuerySet
對象上調(diào)用。因此只要是返回了QuerySet
對象,那么就可以進(jìn)行鏈?zhǔn)秸{(diào)用。比如要獲取2018年度的銷售總額扁耐,那么可以先過濾年份,再求聚合函數(shù)。示例代碼如下:BookOrder.objects.filter(create_time__year=2018).aggregate(total=Sum('price'))
76
-
F表達(dá)式
: 動(dòng)態(tài)的獲取某個(gè)字段上的值俗壹。并且這個(gè)F表達(dá)式,不會真正的去數(shù)據(jù)庫中查詢數(shù)據(jù),他相當(dāng)于只是起一個(gè)標(biāo)識的作用棺禾。比如想要將原來每本圖書的價(jià)格都在原來的基礎(chǔ)之上增加10元缺前,那么可以使用以下代碼來實(shí)現(xiàn):from django.db.models import F Book.objects.update(price=F("price")+10)
77
-
Q表達(dá)式
:使用Q
表達(dá)式包裹查詢條件,可以在條件之間進(jìn)行多種操作逝段。與/或非等亿驾,從而實(shí)現(xiàn)一些復(fù)雜的查詢操作儡蔓。例子如下:- 查找價(jià)格大于100旁振,并且評分達(dá)到4.85以上的圖書:
# 不使用Q表達(dá)式的 books = Book.objects.filter(price__gte=100,rating__gte=4.85) # 使用Q表達(dá)式的 books = Book.objects.filter(Q(price__gte=100)&Q(rating__gte=4.85))
- 查找價(jià)格低于100元卵惦,或者評分低于4分的圖書:
books = Book.objects.filter(Q(price__gte=100)&Q(rating__gte=4.85))
- 獲取價(jià)格大于100,并且圖書名字中不包含”傳“字的圖書:
books = Book.objects.filter(Q(price__gte=100)&~Q(name__icontains='傳'))
- 查找價(jià)格大于100旁振,并且評分達(dá)到4.85以上的圖書:
78objects對象所屬類原理剖析
79-93 queryset api 介紹
94-97 ORM作業(yè)講解
98
ORM模型遷移
遷移命令:
1、makemigrations:將模型生成遷移腳本姥敛。模型所在的app,必須放在settings.py中的INSTALLED_APPS中。這個(gè)命令有以下幾個(gè)常用選項(xiàng):
app_label:后面可以跟一個(gè)或者多個(gè)app阵翎,那么就只會針對這幾個(gè)app生成遷移腳本箱沦。如果沒有任何的app_label,那么會檢查INSTALLED_APPS中所有的app下的模型雇庙,針對每一個(gè)app都生成響應(yīng)的遷移腳本疆前。
--name:給這個(gè)遷移腳本指定一個(gè)名字。
--empty:生成一個(gè)空的遷移腳本。如果你想寫自己的遷移腳本赊窥,可以使用這個(gè)命令來實(shí)現(xiàn)一個(gè)空的文件熄阻,然后自己再在文件中寫遷移腳本秃殉。
99
2、migrate:將新生成的遷移腳本。映射到數(shù)據(jù)庫中巧颈。創(chuàng)建新的表或者修改表的結(jié)構(gòu)畦木。以下一些常用的選項(xiàng):
- app_label:將某個(gè)
app
下的遷移腳本映射到數(shù)據(jù)庫中。如果沒有指定砸泛,那么會將所有在INSTALLED_APPS
中的app
下的模型都映射到數(shù)據(jù)庫中十籍。 - app_label migrationname:將某個(gè)
app
下指定名字的migration
文件映射到數(shù)據(jù)庫中。 - --fake:可以將指定的遷移腳本名字添加到數(shù)據(jù)庫中唇礁。但是并不會把遷移腳本轉(zhuǎn)換為SQL語句勾栗,修改數(shù)據(jù)庫中的表。
- --fake-initial:將第一次生成的遷移文件版本號記錄在數(shù)據(jù)庫中盏筐。但并不會真正的執(zhí)行遷移腳本围俘。
3、showmigrations:查看某個(gè)app下的遷移文件琢融。如果后面沒有app界牡,那么將查看INSTALLED_APPS
中所有的遷移文件。
4漾抬、sqlmigrate:查看某個(gè)遷移文件在映射到數(shù)據(jù)庫中的時(shí)候宿亡,轉(zhuǎn)換的SQL
語句。
migrations中的遷移版本和數(shù)據(jù)庫中的遷移版本對不上怎么辦纳令?
- 找到哪里不一致挽荠,然后使用
python manage.py --fake [版本名字]
,將這個(gè)版本標(biāo)記為已經(jīng)映射平绩。 - 刪除指定
app
下migrations
和數(shù)據(jù)庫表django_migrations
中和這個(gè)app
相關(guān)的版本號圈匆,然后將模型中的字段和數(shù)據(jù)庫中的字段保持一致,再使用命令python manage.py makemigrations
重新生成一個(gè)初始化的遷移腳本捏雌,之后再使用命令python manage.py makemigrations --fake-initial
來將這個(gè)初始化的遷移腳本標(biāo)記為已經(jīng)映射跃赚。以后再修改就沒有問題了。
更多關(guān)于遷移腳本的腹忽。請查看官方文檔:https://docs.djangoproject.com/en/2.0/topics/migrations/
migrate怎么判斷哪些遷移腳本需要執(zhí)行:
他會將代碼中的遷移腳本和數(shù)據(jù)庫中django_migrations
中的遷移腳本進(jìn)行對比,如果發(fā)現(xiàn)數(shù)據(jù)庫中砚作,沒有這個(gè)遷移腳本窘奏,那么就會執(zhí)行這個(gè)遷移腳本。
migrate做了什么事情:
- 將相關(guān)的遷移腳本翻譯成SQL語句葫录,在數(shù)據(jù)庫中執(zhí)行這個(gè)SQL語句着裹。
- 如果這個(gè)SQL語句執(zhí)行沒有問題,那么就會將這個(gè)遷移腳本的名字記錄到
django_migrations
中米同。
執(zhí)行migrate命令的時(shí)候報(bào)錯(cuò)的解決辦法:
原因:
執(zhí)行migrate命令會報(bào)錯(cuò)的原因是骇扇。數(shù)據(jù)庫的django_migrations
表中的遷移版本記錄和代碼中的遷移腳本不一致導(dǎo)致的摔竿。
解決辦法:
使用--fake參數(shù):
首先對比數(shù)據(jù)庫中的遷移腳本和代碼中的遷移腳本。然后找到哪個(gè)不同少孝,之后再使用--fake
继低,將代碼中的遷移腳本添加到django_migrations
中,但是并不會執(zhí)行sql語句稍走。這樣就可以避免每次執(zhí)行migrate
的時(shí)候袁翁,都執(zhí)行一些重復(fù)的遷移腳本。
終極解決方案:
如果代碼中的遷移腳本和數(shù)據(jù)庫中的遷移腳本實(shí)在太多婿脸,就是搞不清了粱胜。那么這時(shí)候就可以使用以下終極解決方案:
- 終極解決方案原理:就是將之前的那些遷移腳本都不用了。重新來過狐树。要將出問題的app下的所有模型和數(shù)據(jù)庫中表保持一致焙压,重新映射。
- 將出問題的app下的所有模型抑钟,都和數(shù)據(jù)庫中的表保持一致涯曲。
- 將出問題的app下的所有遷移腳本文件都刪掉。再在
django_migrations
表中將出問題的app相關(guān)的遷移記錄都刪掉味赃。 - 使用
makemigrations
掀抹,重新將模型生成一個(gè)遷移腳本。 - 使用
migrate --fake-initial
參數(shù)心俗,將剛剛生成的遷移腳本傲武,標(biāo)記為已經(jīng)完成(因?yàn)檫@些模型相對應(yīng)的表,其實(shí)都已經(jīng)在數(shù)據(jù)庫中存在了城榛,不需要重復(fù)執(zhí)行了揪利。) - 可以做其他的映射了。
100 根據(jù)已有的表自動(dòng)生成模型:
在實(shí)際開發(fā)中狠持,有些時(shí)候可能數(shù)據(jù)庫已經(jīng)存在了疟位。如果我們用Django來開發(fā)一個(gè)網(wǎng)站,讀取的是之前已經(jīng)存在的數(shù)據(jù)庫中的數(shù)據(jù)喘垂。那么該如何將模型與數(shù)據(jù)庫中的表映射呢甜刻?根據(jù)舊的數(shù)據(jù)庫生成對應(yīng)的ORM模型,需要以下幾個(gè)步驟:
Django給我們提供了一個(gè)inspectdb的命令正勒,可以非常方便的將已經(jīng)存在的表得院,自動(dòng)的生成模型。想要使用inspectdb自動(dòng)將表生成模型章贞。首先需要在settings.py中配置好數(shù)據(jù)庫相關(guān)信息祥绞。不然就找不到數(shù)據(jù)庫。示例代碼如下:
DATABASES = {
‘default‘: {
‘ENGINE‘: ‘django.db.backends.mysql‘,
‘NAME‘: "migrations_demo",
‘HOST‘: ‘127.0.0.1‘,
‘PORT‘: ‘3306‘,
‘USER‘: ‘root‘,
‘PASSWORD‘: ‘root‘
}
}
比如有以下表:
那么通過python manage.py inspectdb
,就會將表轉(zhuǎn)換為模型后的代碼蜕径,顯示在終端:
from django.db import models
class ArticleArticle(models.Model):
title = models.CharField(max_length=100)
content = models.TextField(blank=True, null=True)
create_time = models.DateTimeField(blank=True, null=True)
author = models.ForeignKey('FrontUserFrontuser', models.DO_NOTHING, blank=True, null=True)
class Meta:
managed = False
db_table = 'article_article'
class ArticleArticleTags(models.Model):
article = models.ForeignKey(ArticleArticle, models.DO_NOTHING)
tag = models.ForeignKey('ArticleTag', models.DO_NOTHING)
class Meta:
managed = False
db_table = 'article_article_tags'
unique_together = (('article', 'tag'),)
class ArticleTag(models.Model):
name = models.CharField(max_length=100)
class Meta:
managed = False
db_table = 'article_tag'
class FrontUserFrontuser(models.Model):
username = models.CharField(max_length=100)
telephone = models.CharField(max_length=11)
class Meta:
managed = False
db_table = 'front_user_frontuser'
以上代碼只是顯示在終端两踏。如果想要保存到文件中。那么可以使用>
重定向輸出到指定的文件兜喻。比如讓他輸出到models.py
文件中梦染。示例命令如下:
python manage.py inspectdb > models.py
以上的命令,只能在終端執(zhí)行虹统,不能在pycharm->Tools->Run manage.py Task...
中使用弓坞。如果只是想要轉(zhuǎn)換一個(gè)表為模型。那么可以指定表的名字车荔。示例命令如下:
python manage.py inspectdb article_article
2渡冻、修正模型:新生成的ORM
模型有些地方可能不太適合使用。比如模型的名字忧便,表之間的關(guān)系等等族吻。那么以下選項(xiàng)還需要重新配置一下:
- 模型名:自動(dòng)生成的模型,是根據(jù)表的名字生成的珠增,可能不是你想要的超歌。這時(shí)候模型的名字你可以改成任何你想要的。
- 模型所屬app:根據(jù)自己的需要蒂教,將相應(yīng)的模型放在對應(yīng)的app中巍举。放在同一個(gè)app中也是沒有任何問題的。只是不方便管理凝垛。
- 模型外鍵引用:將所有使用
ForeignKey
的地方懊悯,模型引用都改成字符串。這樣不會產(chǎn)生模型順序的問題梦皮。另外炭分,如果引用的模型已經(jīng)移動(dòng)到其他的app中了,那么還要加上這個(gè)app的前綴剑肯。 - 讓Django管理模型:將
Meta
下的managed=False
刪掉捧毛,如果保留這個(gè),那么以后這個(gè)模型有任何的修改让网,使用migrate
都不會映射到數(shù)據(jù)庫中呀忧。 - 當(dāng)有多對多的時(shí)候,應(yīng)該也要修正模型溃睹。將中間表注視了而账,然后使用
ManyToManyField
來實(shí)現(xiàn)多對多。并且丸凭,使用ManyToManyField
生成的中間表的名字可能和數(shù)據(jù)庫中那個(gè)中間表的名字不一致福扬,這時(shí)候肯定就不能正常連接了。那么可以通過db_table
來指定中間表的名字惜犀。示例代碼如下:
class Article(models.Model):
title = models.CharField(max_length=100, blank=True, null=True)
content = models.TextField(blank=True, null=True)
author = models.ForeignKey('front.User', models.SET_NULL, blank=True, null=True)
# 使用ManyToManyField模型到表铛碑,生成的中間表的規(guī)則是:article_tags
# 但現(xiàn)在已經(jīng)存在的表的名字叫做:article_tag
# 可以使用db_table,指定中間表的名字
tags = models.ManyToManyField("Tag",db_table='article_tag')
class Meta:
db_table = 'article'
- 表名:切記不要修改表的名字虽界。不然映射到數(shù)據(jù)庫中汽烦,會發(fā)生找不到對應(yīng)表的錯(cuò)誤。
3莉御、執(zhí)行命令python manage.py makemigrations
生成初始化的遷移腳本撇吞。方便后面通過ORM
來管理表。這時(shí)候還需要執(zhí)行命令python manage.py migrate --fake-initial
礁叔,因?yàn)槿绻皇褂?code>--fake-initial牍颈,那么會將遷移腳本會映射到數(shù)據(jù)庫中。這時(shí)候遷移腳本會新創(chuàng)建表琅关,而這個(gè)表之前是已經(jīng)存在了的煮岁,所以肯定會報(bào)錯(cuò)。此時(shí)我們只要將這個(gè)0001-initial
的狀態(tài)修改為已經(jīng)映射涣易,而不真正執(zhí)行映射画机,下次再migrate
的時(shí)候,就會忽略他新症。
4步氏、將Django
的核心表映射到數(shù)據(jù)庫中:Django
中還有一些核心的表也是需要?jiǎng)?chuàng)建的。不然有些功能是用不了的徒爹。比如auth
相關(guān)表荚醒。如果這個(gè)數(shù)據(jù)庫之前就是使用Django
開發(fā)的,那么這些表就已經(jīng)存在了瀑焦‰缜遥可以不用管了。如果之前這個(gè)數(shù)據(jù)庫不是使用Django
開發(fā)的榛瓮,那么應(yīng)該使用migrate
命令將Django
中的核心模型映射到數(shù)據(jù)庫中铺董。