Django模型層的擴展

創(chuàng)建一個Django工程及app

PS D:\test> django-admin startproject modelExplore 
PS D:\test> cd modelExplore 
PS D:\test\modelExplore> python manage.py startapp modelExample 
PS D:\test\modelExplore>

添加app 到settings.py文件中的INSTALLED_APPS配置項中

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'modelExample',
]

配置數(shù)據(jù)庫

使用默認(rèn)的數(shù)據(jù)庫:sqlite3

數(shù)據(jù)庫的配置方法我在 [Django介紹與框架整合掘托,并使用MySQL實現(xiàn)增刪改查] 這篇文章中有過介紹灰粮。

模型

Django為了對各種數(shù)據(jù)庫提供支持沟蔑,因此抽象出一種模型的概念,并提供一套統(tǒng)一的調(diào)用API撞牢。這樣你就可以根據(jù)業(yè)務(wù)需求去選擇數(shù)據(jù)庫祸穷,而不需要面對因數(shù)據(jù)庫的變更而修改代碼,極大地減輕了開發(fā)人員的工作量读恃。

在學(xué)習(xí)模型前,我們先了解ORM(Object Relational Mapping:對象關(guān)系映射)的概念:

用于實現(xiàn)面向?qū)ο缶幊陶Z言里不同類型系統(tǒng)的數(shù)據(jù)之間的轉(zhuǎn)換代态。從效果上說寺惫,它其實是創(chuàng)建了一個可在編程語言里使用的“虛擬對象數(shù)據(jù)庫”。簡單理解蹦疑,就是根據(jù)對象的類型生成表結(jié)構(gòu)西雀,將對象、列表操作轉(zhuǎn)換為sql語句必尼,將sql語句查詢到的結(jié)果轉(zhuǎn)換為對象蒋搜、列表篡撵。

模型實現(xiàn)的就是一種對象關(guān)系映射判莉,那么模型豆挽、屬性、表券盅、字段他們又有哪些不為人知的秘密呢帮哈?

  • 一個模型類在數(shù)據(jù)庫中對應(yīng)一張表
  • 在模型類中定義的屬性對應(yīng)模型對照表中的一個字段。

Django根據(jù)屬性的類型確定以下信息锰镀。

  • 當(dāng)前選擇的數(shù)據(jù)庫支持字段的類型
  • 渲染管理表單時使用的默認(rèn)html控件
  • 在管理站點最低限度的驗證

屬性命名限制

  • 不能是Python的保留關(guān)鍵字(遵循標(biāo)識符規(guī)則)
  • 由于Django的查詢方式娘侍,不允許使用連續(xù)的下劃線

定義模型

我們在modelExample這個目錄下的models.py定義模型,定義模型需要引入django.db中的models,模型類要繼承models.Model類泳炉,一個模型就是一個類憾筏。定義屬性時,需要字段類型花鹅,字段類型被定義在django.db.models.fields目錄下氧腰,為了方便使用,我們將整個django.db.models導(dǎo)入刨肃,我們以創(chuàng)建一個簡單的用戶表為例:

from django.db import models 


# Create your models here. 

class User(models.Model): 
    acocunt = models.CharField(max_length=20) 
    name = models.CharField(max_length=20) 
    passwd = models.CharField(max_length=16) 
    email = models.CharField(max_length=50) 
    sex = models.BooleanField(max_length=1, choices=((0, '男'),(1, '女'),),default=0)

說明:不需要定義主鍵古拴,在生成表時自動添加。

關(guān)系

分類:

  • ForeignKey:一對多真友,將字段定義在多的端中
  • ManyToOneField:多對多黄痪,將字段定義在兩端中
  • OneToOneField:一對一,將字段定義在任意一端中

用一訪問多

  • 格式:對象.模型類小寫_set
  • 示例:grade.students_set

用一訪問一

  • 格式:對象.模型類小寫
  • 示例:grade.students

訪問id

  • 格式:對象.屬性_id
  • 示例:student.sgrade_id

屬性類型

  • AutoField:一個根據(jù)實際ID自動增長的IntegerField盔然,通常不指定桅打,如果不指定一個主鍵字段將自動添加到模型中

Django會為表增加自動增長的主鍵列,每個模型只能有一個主鍵列愈案,如果使用選項設(shè)置某屬性為主鍵列后挺尾,則Django不會再生成默認(rèn)的主鍵列。

  • CharField(max_length=字符長度):字符創(chuàng)刻帚,默認(rèn)的表單樣式是TextInput
  • TextField:大文本字段潦嘶,一般超過4000使用,默認(rèn)的表單控件是Textarea
  • IntegerField:整數(shù)
  • DecimalField(max_digits=None, decimal_places=None):

使用Python的Decimal實例表示的十進(jìn)制的浮點數(shù) 參數(shù)說明: DecimalField.max_digits:位數(shù)總數(shù) DecimalField.decimal_places:小數(shù)點后的數(shù)字位數(shù)

  • FloatField:用Python的float實例來表示的浮點數(shù)
  • BooleanField:True/False字段崇众,此字段的默認(rèn)表單控制是CheckboxInput
  • NullBooleanField:支持null.true,false三種字段
  • DateField([auto_now=False,auto_now_add=False]):

使用Python的datetime.date實例表示的日期 參數(shù)說明: DateField.auto_now:每次保存對象時掂僵,自動設(shè)置該字段為當(dāng)前時間,用于“最后一次修改“的時間戳顷歌,他總是使用當(dāng)前日期锰蓬,默認(rèn)為False DateField.auto_now_add:當(dāng)前對象第一次被創(chuàng)建時設(shè)置當(dāng)前時間,用于創(chuàng)建的時間戳眯漩,他總是使用當(dāng)前日期芹扭,默認(rèn)為False 說明: 該字段默認(rèn)對應(yīng)的表單控件是一個TextInput麻顶。在管理員站點添加了一個JavaScript寫的日歷控件,和一個Today的快捷按鈕舱卡,包含了一個額外的invalid_date錯誤信息鍵 注意: Auto_now_add,auto_now and default 這些設(shè)置是相互排斥的辅肾,他們之間的任何組合將會發(fā)生錯誤的結(jié)果。

  • TimeField:使用Python的datetime.time實例表示的時間轮锥,參數(shù)同DateField

  • DateTimeField:使用Python的datetime矫钓,datetime實例表示的日期和時間,參數(shù)同DateField

  • FileField:一個上傳文件的字段

  • ImageField:繼承了FileField的所有屬性和方法舍杜,但對上傳的對象進(jìn)行校驗新娜,確保他是個有效的image

  • 外鍵ForeignKey

from django.db import models 

class Grades(models.Model): 
    class_name = models.CharField(max_length=20) 
    headteacher = models.CharField(max_length=20) 
    students_count = models.IntegerField(2)

class student(models.Model): 
    student_num = models.CharField(max_length=20)
    student_name = models.CharField(max_length=20) 
    student_sex = models.BooleanField(max_length=1, choices=((0, '男'),(1, '女'),),default=0)
    student_birth = models.DateField(auto_now_add=true)
    student_grade = models.ForeignKey('Grades')

屬性選項

  1. 通過屬性選項,可以實現(xiàn)對屬性的約束
  2. 在屬性對象通過關(guān)鍵字參數(shù)指定
  • Null:如果為True既绩,Django將控制以null存儲到數(shù)據(jù)庫中概龄,默認(rèn)值是False

  • Blank:如果為True,則該字段允許為空白饲握,默認(rèn)值是False

    注意:null是數(shù)據(jù)庫范疇的概念私杜,blank是表單驗證范疇的

  • Db_column:字段的名稱,如果未指定互拾,則使用屬性的名稱

  • Db_index:若值為True歪今,則在表中會為此字段創(chuàng)建索引

  • Default:默認(rèn)值

  • Primary_key:若為True,則該字段會成為模型的主鍵字段

  • Unique:如果為True颜矿,這個字段在表中必須有唯一值

元選項:在模型類定義中定義Meta類寄猩,用于設(shè)置元信息

Class Stucent(models.Model):
    # someField
    Class Meta:
        db_table = 'stucents' # 定義數(shù)據(jù)表名,推薦使用小寫字母骑疆,如果不寫田篇,數(shù)據(jù)表名默認(rèn)為項目名小寫_類名小寫
        ordering=['id']  # 對象的默認(rèn)排序字段,獲取對象的列表時使用箍铭。
        # ordering = ['id']:升序泊柬;ordering = ['-id']:降序
        # 注意:排序會增加數(shù)據(jù)庫的開銷。

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

在以往的開發(fā)模式中诈火,我們通常都是設(shè)計好數(shù)據(jù)庫表后兽赁,將其創(chuàng)建出來,然后通過sql來進(jìn)行查詢冷守,而在Django中刀崖,我們可以省去數(shù)據(jù)庫表的設(shè)計和創(chuàng)建步驟,我們定義模型其實就是對表的設(shè)計拍摇,執(zhí)行遷移就是創(chuàng)建數(shù)據(jù)庫表亮钦。修改模型后只需要再遷移即可

第一步:生成遷移文件

在我們的工程目錄下執(zhí)行以下命令:python manage.py makemigrations

PS D:\modelExplore> python manage.py makemigrations 
Database version : 5.5.53 
Migrations for 'firstApp': firstApp\migrations\0001_initial.py 
- Create model User 
PS D:\modelExplore>

如果控制臺會打印出類似以上的內(nèi)容,此時會在modelExample app目錄下的migrations目錄下生成一個遷移文件充活,但是現(xiàn)在還沒有在數(shù)據(jù)庫中創(chuàng)建表蜂莉。

第二步:執(zhí)行遷移

在執(zhí)行完上一步后蜡娶,只是生成了一個遷移文件,此時還沒有在數(shù)據(jù)庫中創(chuàng)建表映穗,我們需要執(zhí)行以下命令來生成數(shù)據(jù)表:python manage.py migrate

PS D:\modelExplore> python manage.py migrate 
Database version : 5.5.53 
Operations to perform: Apply all migrations: admin, auth, contenttypes, firstApp, sessions Running migrations: 
Applying firstApp.0001_initial... OK 
PS D:\modelExplore>

執(zhí)行以上的命令相當(dāng)于執(zhí)行SQL語句創(chuàng)建了數(shù)據(jù)表窖张。看到類似于上文的結(jié)果表示成功男公,可以去數(shù)據(jù)庫中查看是否已經(jīng)創(chuàng)建了這張表荤堪。表名是你的appName_modelName連接在一起的合陵,當(dāng)然了枢赔,表名也是可以自定義的(在元選項中有過說明)。

模型成員

類屬性: objects,他是Manager類型的一個對象拥知,作用是與數(shù)據(jù)庫進(jìn)行交互踏拜。當(dāng)定義模型類時,沒有指定管理器則Django默認(rèn)為模型創(chuàng)建一個名為objects的管理器低剔。

自定義模型管理器:

class student(models.Model): 

    stuObj = models.Manager() # 自定義模型管理器,此時再去使用objects就會報錯了

    student_num = models.CharField(max_length=20)
    student_name = models.CharField(max_length=20) 
    student_sex = models.BooleanField(max_length=1, choices=((0, '男'),(1, '女'),),default=0)
    student_birth = models.DateField(auto_now_add=true)
    student_grade = models.ForeignKey('Grades')

當(dāng)模型指定模型管理器速梗。Django就不在為模型類生成objects模型管理器了。模型管理器可以創(chuàng)建多個襟齿。

自定義管理器Manager類: 模型管理器是Django的模型進(jìn)行與數(shù)據(jù)庫進(jìn)行交互的接口姻锁,一個模型類可以有多個模型管理器

作用:

  • 向管理器中添加額外的方法
  • 修改管理器返回的原始查詢集----重寫get_queryset()方法。

實例:

Class StudentsManager(models.Manager): 
    get_queryset(self): 
        return super(StudentsManager,self).getqueryset().filter(isDelete=False)


class student(models.Model): 

    # 為對象創(chuàng)建一個模型管理器
    stuObj = objects_new = StudnetsManager()

    student_num = models.CharField(max_length=20)
    student_name = models.CharField(max_length=20) 
    student_sex = models.BooleanField(max_length=1, choices=((0, '男'),(1, '女'),),default=0)
    student_birth = models.DateField(auto_now_add=true)
    student_grade = models.ForeignKey('Grades')

創(chuàng)建對象:

目的:向數(shù)據(jù)庫中添加數(shù)據(jù) 當(dāng)創(chuàng)建對象時猜欺,Django不會對數(shù)據(jù)庫進(jìn)行讀寫操作位隶,當(dāng)調(diào)用save()方法時才與數(shù)據(jù)庫交互,將對象保存到數(shù)據(jù)庫开皿。

注意:__init__方法已經(jīng)在基類(父類)中使用涧黄,在自定義的模型中無法使用

方法:

  • 在模型類中增加一個類方法
  • 在自定義管理器中添加一個方法

此處亂七八糟的呢

@classmethod 
def createStudents(cls,name,age , gender, contend…): 
    student = cls(sname = name , sage = age…) 
    return student 

stu.createStudents(…) 

# 在自定義管理器中添加一個方法 在StudentsManager中創(chuàng)建一個方法 
def createStudents(self,name,age , gender, contend…): 
    # 可以直接創(chuàng)建一個對象,但是這種方式不通用赋荆,限制了這個管理器笋妥。 
    stu = Students()

# 在通常情況下,我們使用以下的方法創(chuàng)建窄潭,這樣什么對象調(diào)用就是什么對象 
stu2 = self.model() 
stu2.sname = name … Print(type(stu2)) 
student = cls(sname = name , sage = age…) 
return student stu.obj.createStudents
# 定義一個類方法創(chuàng)建對象,此方法要創(chuàng)建在Students類中

模型查詢

查詢集:

查詢集是表示從數(shù)據(jù)庫中獲取的對象的集合春宣,查詢集可以有多個過濾器,過濾器就是一個函數(shù)嫉你,基于所給的參數(shù)限制查詢集結(jié)果月帝。從sql角度來說,查詢集合select語句等價均抽,過濾器就像where條件嫁赏。

1在管理器上調(diào)用過濾器方法返回結(jié)果集
2查詢集經(jīng)過過濾器篩選后返回新的查詢集,所以我們可以寫成鏈?zhǔn)秸{(diào)用
3惰性執(zhí)行:創(chuàng)建查詢集不會帶來任何數(shù)據(jù)庫的訪問油挥,直到調(diào)數(shù)據(jù)時潦蝇,才會訪問數(shù)據(jù)庫
4直接訪問數(shù)據(jù)的情況:
迭代:
序列化:
與if合用:
5返回查詢集的方法稱為過濾器
all():返回查詢集中的所有數(shù)據(jù)
filter():返回符合條件的數(shù)據(jù) :

  • filter(鍵=值);

  • filter(鍵=值款熬,鍵=值);

  • filter(鍵=值).filter(鍵=值)

  • 多條件是and查詢

    exclude():過濾掉符合條件的數(shù)據(jù)
    order_by():排序
    values():一條數(shù)據(jù)就是一個對象(字典)攘乒,返回一個列表
    6返回單個數(shù)據(jù)
    get():返回一個滿足條件的對象
    注意:如果沒有找到符合條件的對象贤牛,會引發(fā)‘模型類DoesNotExist’異常
    如果找到了多個對象,也會引發(fā)‘模型類MultipleObjectsReturned’異常
    count():返回當(dāng)前查詢集中的對象個數(shù)
    first():返回當(dāng)前查詢集中的第一個對象
    last():返回當(dāng)前查詢集中的最后一個對象
    exists():判斷查詢集中是否有數(shù)據(jù)则酝,如果有返回True殉簸,否則返回False
    7限制查詢集:查詢集返回列表,可以使用下標(biāo)的方法進(jìn)行限制沽讹,等同于SQL中的limits
    students.objects.all()[0:5]

    注意下標(biāo)不能是負(fù)數(shù)

    實現(xiàn)分頁功能

8查詢集的緩存
概述:每個查詢集都包含一個緩存般卑,來最小化的對數(shù)據(jù)庫訪問
在新建的查詢集中,緩存首次為空爽雄,第一次對查詢集求值蝠检,會發(fā)生數(shù)據(jù)緩存。挚瘟,django會將查詢出來的數(shù)據(jù)做緩存叹谁,并返回查詢結(jié)構(gòu),以后的查詢直接使用查詢緩存的方式查詢乘盖。
9字段查詢
概述:
1實現(xiàn)了SQL中的where語句作為方法filter()焰檩、exclude()、get()的參數(shù)
2語法:屬性名稱比較運算符=值
3外鍵:屬性名id
4轉(zhuǎn)義:類似SQL中的like語句中使用%為了匹配占位订框。
例:filter(sname__contains=”%”)
比較運算符:
1exact判斷析苫,大小寫敏感,例filter(isDelete=False)
2contailns:是否包含布蔗,大小寫敏感:例:student.objects.filter(sname__contains=’于’)
3startswith/endswith:以value開頭或結(jié)尾藤违,大小寫敏感
以上四個在前面加上一個I,就表示不區(qū)分大小寫:iexact/icontains/istartswith
4isnull/isnotnull :是否為空;filter(sname__isnull=False)
5in : 是否包含纵揍。filter(pk__in=[2,4,6,8,])
6gt/gte/lt/lte : 大于/大于等于/小于/小于等于顿乒;filter(sage__gt=50)
7year/month/day/week_day/hour/minute/second : 日期 filter(last_time__year = 2018)
8跨關(guān)聯(lián)查詢:
處理join語句:
語法:模型類名
屬性名
_比較運算符
# 描述中帶有小白兔關(guān)鍵字的數(shù)據(jù)屬于哪個班級
Grades.objects.filter(Students__scontend__contains=’小白兔’)
9快速查詢:pk:代表的主鍵
聚合函數(shù):使用aggregate()函數(shù)返回聚合函數(shù)的值
1Avg:
2Count
3Max/Min/Sum
from django.db.model import Max
Students.objects.aggregate(Max(‘sage’))
F對象:可以使用模型的A屬性與B屬性進(jìn)行比較
from django.db.model import F
Grades.objects.filter(ggirlnum__gt=F(‘gboynum’) + 20)
支持F對象算數(shù)運算和時間運算
Q對象
概述:過濾器的方法中的關(guān)鍵字參數(shù),條件為and方式
需求:進(jìn)行or查詢
解決:使用Q對象
from django.db.model import Q
Students.objects.filter(Q(pk__lt=3) | Q(sage__gt=50))
# 只有一個Q的時候泽谨,與沒有Q相同
Students.objects.filter(Q(pk__lt=3))
# 在Q前加一個~璧榄,表示取反
Students.objects.filter(~Q(pk__lt=3))

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市吧雹,隨后出現(xiàn)的幾起案子骨杂,更是在濱河造成了極大的恐慌,老刑警劉巖雄卷,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搓蚪,死亡現(xiàn)場離奇詭異,居然都是意外死亡丁鹉,警方通過查閱死者的電腦和手機妒潭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門悴能,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人雳灾,你說我怎么就攤上這事漠酿。” “怎么了谎亩?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵炒嘲,是天一觀的道長。 經(jīng)常有香客問我匈庭,道長夫凸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任嚎花,我火速辦了婚禮寸痢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘紊选。我一直安慰自己,他們只是感情好道逗,可當(dāng)我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布兵罢。 她就那樣靜靜地躺著,像睡著了一般滓窍。 火紅的嫁衣襯著肌膚如雪卖词。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天吏夯,我揣著相機與錄音此蜈,去河邊找鬼。 笑死噪生,一個胖子當(dāng)著我的面吹牛裆赵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播跺嗽,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼战授,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了桨嫁?” 一聲冷哼從身側(cè)響起植兰,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎璃吧,沒想到半個月后楣导,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡畜挨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年筒繁,在試婚紗的時候發(fā)現(xiàn)自己被綠了彬坏。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡膝晾,死狀恐怖栓始,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布躏将,位于F島的核電站豁延,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏量没。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望佳谦。 院中可真熱鬧,春花似錦滋戳、人聲如沸钻蔑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咪笑。三九已至,卻和暖如春娄涩,著一層夾襖步出監(jiān)牢的瞬間窗怒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工蓄拣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留扬虚,地道東北人。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓球恤,卻偏偏與公主長得像辜昵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子碎捺,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,472評論 2 348

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