django學(xué)習(xí)筆記5-數(shù)據(jù)庫 (42-100)

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)
  1. 使用makemigrations生成遷移腳本文件
    python manage.py makemigrations

  2. 使用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)然也可以自定義查詢對象寨典。這部分功能會在后面講到氛雪。

  1. 根據(jù)主鍵進(jìn)行查找:使用主鍵進(jìn)行查找∷食桑可以使用objects.get方法报亩。然后傳遞pk=xx的方式進(jìn)行查找。示例代碼如下:
    book = Book.objects.get(pk=2)
    
  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í)間牵辣?

  1. navie時(shí)間:不知道自己的時(shí)間表示的是哪個(gè)時(shí)區(qū)的摔癣。也就是不知道自己幾斤幾兩。比較幼稚纬向。
  2. 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ù):

  1. auto_now:在每次這個(gè)數(shù)據(jù)保存的時(shí)候余舶,都使用當(dāng)前的時(shí)間。比如作為一個(gè)記錄修改日期的字段锹淌,可以將這個(gè)屬性設(shè)置為True匿值。
  2. 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_nowauto_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è)Fieldnull=False赎离,如果你沒有給這個(gè)Field傳遞任何值逛犹,那么Django也會使用一個(gè)空的字符串""來作為默認(rèn)值存儲進(jìn)去。因此如果再使用null=True梁剔,Django會產(chǎn)生兩種空值的情形(NULL或者空字符串)虽画。如果想要在表單驗(yàn)證的時(shí)候允許這個(gè)字符串為空,那么建議使用blank=True荣病。如果你的FieldBooleanField码撰,那么對應(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)的示例代碼如下:

  1. 在同一個(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)系

一對多

  1. 應(yīng)用場景:比如文章和作者之間的關(guān)系舷蒲。一個(gè)文章只能由一個(gè)作者編寫,但是一個(gè)作者可以寫多篇文章友多。文章和作者之間的關(guān)系就是典型的多對一的關(guān)系。
  2. 實(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

一對一:

  1. 在Django中一對一是通過models.OnetToOneField來實(shí)現(xiàn)的盈厘。這個(gè)OneToOneField其實(shí)本質(zhì)上就是一個(gè)外鍵,只不過這個(gè)外鍵有一個(gè)唯一約束(unique key)涝缝,來實(shí)現(xiàn)一對一扑庞。
  2. 以后如果想要反向引用,那么是通過引用的模型的名字轉(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

多對多:

  1. 應(yīng)用場景:比如文章和標(biāo)簽的關(guān)系租悄。一篇文章可以有多個(gè)標(biāo)簽谨究,一個(gè)標(biāo)簽可以被多個(gè)文章所引用。因此標(biāo)簽和文章的關(guān)系是典型的多對多的關(guān)系泣棋。

  2. 實(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è)外鍵把敢,引用到articletag兩張表的主鍵寄摆。

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的方式來使用的勾邦。以下將那些常用的查詢條件來一一解釋。

  1. exact:在底層會被翻譯成=

  2. 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)榇蟛糠智闆rexactiexact又是等價(jià)的,因此我們以后直接使用field=xxx就可以了沾鳄。

63

  1. QuerySet.query:query可以用來查看這個(gè)ORM查詢語句最終被翻譯成的SQL語句慨飘。但是query只能被用在QuerySet對象上,不能用在普通的ORM模型上译荞。因此如果你的查詢語句是通過get來獲取數(shù)據(jù)的瓤的,那么就不能使用query,因?yàn)?code>get返回的是滿足條件的ORM模型吞歼,而不是QuerySet圈膏。如果你是通過filter等其他返回QuerySet的方法查詢的,那么就可以使用query篙骡。

  2. contains:使用大小寫敏感的判斷稽坤,某個(gè)字符串是否在指定的字段中丈甸。這個(gè)判斷條件會使用大小敏感,因此在被翻譯成SQL語句的時(shí)候尿褪,會使用like binary睦擂,而like binary就是使用大小寫敏感的。

  3. icontains:使用大小寫不敏感的判斷杖玲,某個(gè)字符串是否被包含在指定的字段中顿仇。這個(gè)查詢語句在被翻譯成SQL的時(shí)候,使用的是like摆马,而likeMySQL層面就是不區(qū)分大小寫的夺欲。

  4. contains和icontains:在被翻譯成SQL的時(shí)候使用的是%hello%,就是只要整個(gè)字符串中出現(xiàn)了hello都能過夠被找到今膊,而iexact沒有百分號,那么意味著只有完全相等的時(shí)候才會被匹配到伞剑。


64

  1. 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_namearticles,因此你不能再使用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

  1. gt、gte伦忠、lt省核、lte:代表的是大于、大于等于昆码、小于气忠、小于等于的條件。示例代碼如下:
    articles = Article.objects.filter(id__lte=3)
    

66

  1. startswith赋咽、istartswith旧噪、endswith、iendswith:表示以某個(gè)值開始脓匿,不區(qū)分大小寫的以某個(gè)值開始淘钟、以某個(gè)值結(jié)束、不區(qū)分大小寫的以某個(gè)值結(jié)束陪毡。示例代碼如下:
    articles = Article.objects.filter(title__endswith="hello")
    

67

  1. 關(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)
      

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

  1. 所有的聚合函數(shù)都是放在django.db.models下面。
  2. 聚合函數(shù)不能夠單獨(dú)的執(zhí)行兴革,需要放在一些可以執(zhí)行聚合函數(shù)的方法下面中去執(zhí)行绎晃。比如aggregate。示例代碼如下:
    result = Book.objects.aggregate(Avg("price"))
    
  3. 聚合函數(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í)示例代碼如下:
    result = Book.objects.aggregate(avg=Avg("price"))
    
    以上傳遞了關(guān)鍵字參數(shù)avg=Avg("price"),那么以后Avg聚合函數(shù)執(zhí)行完成的名字就叫做avg蟹地。
  4. aggregate:這個(gè)方法不會返回一個(gè)QuerySet對象,而是返回一個(gè)字典藤为。這個(gè)字典中的key就是聚合函數(shù)的名字怪与,值就是聚合函數(shù)執(zhí)行后的結(jié)果。

72

  1. aggregateannotate的相同和不同:
    • 相同:這兩個(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

  1. 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

  1. MaxMin:求指定字段的最大值和最小值晚伙。示例代碼如下:
    result = Author.objects.aggregate(max=Max("age"),min=Min("age"))
    

75

  1. Sum:求某個(gè)字段值的總和恢恼。示例代碼如下:
    result = BookOrder.objects.aggregate(total=Sum('price'))
    
    aggregateannotate方法可以在任何的QuerySet對象上調(diào)用。因此只要是返回了QuerySet對象,那么就可以進(jìn)行鏈?zhǔn)秸{(diào)用。比如要獲取2018年度的銷售總額扁耐,那么可以先過濾年份,再求聚合函數(shù)。示例代碼如下:
    BookOrder.objects.filter(create_time__year=2018).aggregate(total=Sum('price'))
    

76

  1. 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

  1. 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='傳'))
      

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ù)庫中的遷移版本對不上怎么辦纳令?

  1. 找到哪里不一致挽荠,然后使用python manage.py --fake [版本名字],將這個(gè)版本標(biāo)記為已經(jīng)映射平绩。
  2. 刪除指定appmigrations和數(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做了什么事情:

  1. 將相關(guān)的遷移腳本翻譯成SQL語句葫录,在數(shù)據(jù)庫中執(zhí)行這個(gè)SQL語句着裹。
  2. 如果這個(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í)候就可以使用以下終極解決方案:

  1. 終極解決方案原理:就是將之前的那些遷移腳本都不用了。重新來過狐树。要將出問題的app下的所有模型和數(shù)據(jù)庫中表保持一致焙压,重新映射。
  2. 將出問題的app下的所有模型抑钟,都和數(shù)據(jù)庫中的表保持一致涯曲。
  3. 將出問題的app下的所有遷移腳本文件都刪掉。再在django_migrations表中將出問題的app相關(guān)的遷移記錄都刪掉味赃。
  4. 使用makemigrations掀抹,重新將模型生成一個(gè)遷移腳本。
  5. 使用migrate --fake-initial參數(shù)心俗,將剛剛生成的遷移腳本傲武,標(biāo)記為已經(jīng)完成(因?yàn)檫@些模型相對應(yīng)的表,其實(shí)都已經(jīng)在數(shù)據(jù)庫中存在了城榛,不需要重復(fù)執(zhí)行了揪利。)
  6. 可以做其他的映射了。

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‘
}
}
比如有以下表:


20190123223059415220.png
20190123223059552906.png
20190123223059666180.png
20190123223059778478.png

那么通過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ù)庫中铺董。

原文地址:https://www.cnblogs.com/zheng-weimin/p/10311847.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市禀晓,隨后出現(xiàn)的幾起案子精续,更是在濱河造成了極大的恐慌,老刑警劉巖粹懒,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件重付,死亡現(xiàn)場離奇詭異,居然都是意外死亡凫乖,警方通過查閱死者的電腦和手機(jī)确垫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門弓颈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人删掀,你說我怎么就攤上這事翔冀。” “怎么了披泪?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵纤子,是天一觀的道長。 經(jīng)常有香客問我款票,道長控硼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任艾少,我火速辦了婚禮卡乾,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘缚够。我一直安慰自己说订,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布潮瓶。 她就那樣靜靜地躺著陶冷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪毯辅。 梳的紋絲不亂的頭發(fā)上埂伦,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機(jī)與錄音思恐,去河邊找鬼沾谜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛胀莹,可吹牛的內(nèi)容都是我干的基跑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼描焰,長吁一口氣:“原來是場噩夢啊……” “哼媳否!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起荆秦,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤篱竭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后步绸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掺逼,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年瓤介,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吕喘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赘那。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖氯质,靈堂內(nèi)的尸體忽然破棺而出漓概,到底是詐尸還是另有隱情,我是刑警寧澤病梢,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站梁肿,受9級特大地震影響蜓陌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吩蔑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一钮热、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧烛芬,春花似錦隧期、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至遣臼,卻和暖如春性置,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背揍堰。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工鹏浅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人屏歹。 一個(gè)月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓隐砸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蝙眶。 傳聞我的和親對象是個(gè)殘疾皇子季希,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容