Django学习小记[2] —— Model
開始學(xué)習(xí)django的model了,學(xué)習(xí)django的目的很簡(jiǎn)單,就是我想用django搭建一個(gè)自己的博客,現(xiàn)在開源的已經(jīng)有django-zinnia這個(gè)博客引擎了,但是想要看懂它,并且修改它,就必須過(guò)django這一關(guān)。之前對(duì)django的了解,僅僅限于用到了什么,就知道什么,缺乏系統(tǒng)的學(xué)習(xí),所以要把django的文檔都過(guò)一遍,做一下簡(jiǎn)單的筆記。
今天的主題是Model,Model就是MVC中的M,代表的數(shù)據(jù)對(duì)象,反映到數(shù)據(jù)庫(kù)中就是數(shù)據(jù)表,Model中的屬性是表的一列,Django對(duì)Model進(jìn)行了封裝,對(duì)Model提供了豐富的查詢接口,反映到數(shù)據(jù)庫(kù)中,就是提供了豐富的select查詢功能,這就是Django的強(qiáng)大之處。
先來(lái)看一個(gè)簡(jiǎn)單的例子,在一個(gè)app中的models.py中,定義一個(gè)Model:
<code class="hljs python" style="font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:undefined; padding:0.5em; color:rgb(248,248,242); background-color:rgb(35,36,31); display:block; margin-top:0px!important"><span class="hljs-keyword" style="color:#f92672;margin-top:0px!important">from</span> django.db <span class="hljs-keyword" style="color:#f92672;">import</span> models<span class="hljs-class" style=""><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">class</span> <span class="hljs-title" style="">Person</span><span class="hljs-params" style="">(models.Model)</span>:</span>first_name = models.CharField(max_length=<span class="hljs-number" style="color:#ae81ff;">30</span>)last_name = models.CharField(max_length=<span class="hljs-number" style="color:#ae81ff;">30</span>) </code>所有的Model都繼承自django.db.models.Model類,Model類的每一個(gè)屬性都繼承自django.db.models.Field,這個(gè)Field有幾個(gè)作用:
- 決定該Field在數(shù)據(jù)庫(kù)中的類型
- 決定該Field在前端上如何顯示
- 做簡(jiǎn)單的驗(yàn)證
Django有很多內(nèi)置的Field,當(dāng)然也可以自定義。
好,下面我們來(lái)重點(diǎn)說(shuō)一下在Django中如何實(shí)現(xiàn)關(guān)系型數(shù)據(jù)庫(kù)的那三種典型關(guān)系:多對(duì)一,多對(duì)多,一對(duì)一
多對(duì)一
實(shí)現(xiàn)多對(duì)一,是使用django.db.models.ForeignKey類,ForeignKey需要一個(gè)positional的參數(shù)來(lái)指定本Model關(guān)聯(lián)的Model,ForeignKey關(guān)聯(lián)的Model是“一”,ForeignKey所在的Model是“多”,比如汽車和制造商的例子,一個(gè)汽車只能屬于一個(gè)制造商,但是一個(gè)制造商有多個(gè)汽車,這個(gè)關(guān)系,用Django的Model來(lái)表示,就是:
<code class="hljs python" style="font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:undefined; padding:0.5em; color:rgb(248,248,242); background-color:rgb(35,36,31); display:block; margin-top:0px!important"><span class="hljs-class" style="margin-top:0px!important"><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">class</span> <span class="hljs-title" style="">Manufacturer</span><span class="hljs-params" style="">(models.Model)</span>:</span>name = models.CharField(max_length=<span class="hljs-number" style="color:#ae81ff;">30</span>)<span class="hljs-class" style=""><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">class</span> <span class="hljs-title" style="">Car</span><span class="hljs-params" style="">(models.Model)</span>:</span>Manufacturer = models.ForeignKey(Manufacturer)name = models.CharField(max_length=<span class="hljs-number" style="color:#ae81ff;">30</span>) </code>該關(guān)系,用sql語(yǔ)句來(lái)表示,就是:
<code class="hljs sql" style="font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:undefined; padding:0.5em; color:rgb(248,248,242); background-color:rgb(35,36,31); display:block; margin-top:0px!important"><span class="hljs-operator" style="margin-top:0px!important"><span class="hljs-keyword" style="color:#f92672;margin-top:0px!important">CREATE</span> <span class="hljs-keyword" style="color:#f92672;">TABLE</span> <span class="hljs-string" style="color:#e6db74;">`model_test_manufacturer`</span> (<span class="hljs-string" style="color:#e6db74;">`id`</span> <span class="hljs-keyword" style="color:#f92672;">integer</span> AUTO_INCREMENT <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> <span class="hljs-keyword" style="color:#f92672;">PRIMARY</span> <span class="hljs-keyword" style="color:#f92672;">KEY</span>,<span class="hljs-string" style="color:#e6db74;">`name`</span> <span class="hljs-keyword" style="color:#f92672;">varchar</span>(<span class="hljs-number" style="color:#ae81ff;">30</span>) <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> );</span> <span class="hljs-operator" style=""><span class="hljs-keyword" style="color:#f92672;margin-top:0px!important">CREATE</span> <span class="hljs-keyword" style="color:#f92672;">TABLE</span> <span class="hljs-string" style="color:#e6db74;">`model_test_car`</span> (<span class="hljs-string" style="color:#e6db74;">`id`</span> <span class="hljs-keyword" style="color:#f92672;">integer</span> AUTO_INCREMENT <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> <span class="hljs-keyword" style="color:#f92672;">PRIMARY</span> <span class="hljs-keyword" style="color:#f92672;">KEY</span>,<span class="hljs-string" style="color:#e6db74;">`Manufacturer_id`</span> <span class="hljs-keyword" style="color:#f92672;">integer</span> <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span>,<span class="hljs-string" style="color:#e6db74;">`name`</span> <span class="hljs-keyword" style="color:#f92672;">varchar</span>(<span class="hljs-number" style="color:#ae81ff;">30</span>) <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> );</span> <span class="hljs-operator" style=""><span class="hljs-keyword" style="color:#f92672;margin-top:0px!important">ALTER</span> <span class="hljs-keyword" style="color:#f92672;">TABLE</span> <span class="hljs-string" style="color:#e6db74;">`model_test_car`</span> <span class="hljs-keyword" style="color:#f92672;">ADD</span> <span class="hljs-keyword" style="color:#f92672;">CONSTRAINT</span> <span class="hljs-string" style="color:#e6db74;">`Manufacturer_id_refs_id_da7168cb`</span> <span class="hljs-keyword" style="color:#f92672;">FOREIGN</span> <span class="hljs-keyword" style="color:#f92672;">KEY</span> (<span class="hljs-string" style="color:#e6db74;">`Manufacturer_id`</span>) <span class="hljs-keyword" style="color:#f92672;">REFERENCES</span> <span class="hljs-string" style="color:#e6db74;">`model_test_manufacturer`</span> (<span class="hljs-string" style="color:#e6db74;">`id`</span>);</span> </code>增刪操作:
<code class="hljs python" style="font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:undefined; padding:0.5em; color:rgb(248,248,242); background-color:rgb(35,36,31); display:block; margin-top:0px!important"><span class="hljs-prompt" style="color:#e6db74;margin-top:0px!important">>>> </span><span class="hljs-keyword" style="color:#f92672;">from</span> model_test.models <span class="hljs-keyword" style="color:#f92672;">import</span> Car <span class="hljs-prompt" style="color:#e6db74;">>>> </span><span class="hljs-keyword" style="color:#f92672;">from</span> model_test.models <span class="hljs-keyword" style="color:#f92672;">import</span> Manufacturer <span class="hljs-prompt" style="color:#e6db74;">>>> </span>m = Manufacturer.objects.get(name=<span class="hljs-string" style="color:#e6db74;">"xxx"</span>) <span class="hljs-prompt" style="color:#e6db74;">>>> </span>m.car_set.all() [] <span class="hljs-prompt" style="color:#e6db74;">>>> </span>m.car_set.create(name=<span class="hljs-string" style="color:#e6db74;">"yyy"</span>) <Car: Car object> <span class="hljs-prompt" style="color:#e6db74;">>>> </span>c = Car(name=<span class="hljs-string" style="color:#e6db74;">"zzz"</span>) <span class="hljs-prompt" style="color:#e6db74;">>>> </span>m.car_set.add(c) </code>關(guān)于多對(duì)一更多的內(nèi)容,參考:Many-to-One
多對(duì)多
要實(shí)現(xiàn)多對(duì)多,就要使用django.db.models.ManyToManyField類,和ForeignKey一樣,它也有一個(gè)positional的參數(shù),用來(lái)指定和它關(guān)聯(lián)的Model。
如果不僅僅需要知道兩個(gè)Model之間是多對(duì)多的關(guān)系,還需要知道這個(gè)關(guān)系的更多信息,比如Person和Group是多對(duì)多的關(guān)系,除了知道一個(gè)Person屬于哪個(gè)Group之外,如果還想知道這個(gè)Person是什么時(shí)候加入這個(gè)Group的,那么就需要有一個(gè)中間表來(lái)記錄這些信息,那就用到了ManyToManyFiled的一個(gè)optional參數(shù): through,如下面的例子:
<code class="hljs python" style="font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:undefined; padding:0.5em; color:rgb(248,248,242); background-color:rgb(35,36,31); display:block; margin-top:0px!important"><span class="hljs-class" style="margin-top:0px!important"><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">class</span> <span class="hljs-title" style="">Person</span><span class="hljs-params" style="">(models.Model)</span>:</span> name = models.CharField(max_length=<span class="hljs-number" style="color:#ae81ff;">30</span>)<span class="hljs-function" style="color:#f92672;"><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">def</span> <span class="hljs-title" style="color:#a6e22e;">__unicode__</span><span class="hljs-params" style="color:#f8f8f2;">(self)</span>:</span> <span class="hljs-keyword" style="color:#f92672;">return</span> self.name<span class="hljs-class" style=""><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">class</span> <span class="hljs-title" style="">Group</span><span class="hljs-params" style="">(models.Model)</span>:</span>name = models.CharField(max_length=<span class="hljs-number" style="color:#ae81ff;">30</span>)members = models.ManyToManyField(Person, through=<span class="hljs-string" style="color:#e6db74;">'Membership'</span>)<span class="hljs-function" style="color:#f92672;"><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">def</span> <span class="hljs-title" style="color:#a6e22e;">__unicode__</span><span class="hljs-params" style="color:#f8f8f2;">(self)</span>:</span><span class="hljs-keyword" style="color:#f92672;">return</span> self.name<span class="hljs-class" style=""><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">class</span> <span class="hljs-title" style="">Membership</span><span class="hljs-params" style="">(models.Model)</span>:</span>person = models.ForeignKey(Person)group = models.ForeignKey(Group)date_joined = models.DateField()invite_person = models.CharField(max_length=<span class="hljs-number" style="color:#ae81ff;">30</span>) </code>在中間表中,通過(guò)外鍵關(guān)聯(lián)到Person和Group,其實(shí),就是兩個(gè)多對(duì)一的關(guān)系,上面對(duì)應(yīng)的SQL語(yǔ)句為:
<code class="hljs sql" style="font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:undefined; padding:0.5em; color:rgb(248,248,242); background-color:rgb(35,36,31); display:block; margin-top:0px!important"><span class="hljs-operator" style="margin-top:0px!important"><span class="hljs-keyword" style="color:#f92672;margin-top:0px!important">CREATE</span> <span class="hljs-keyword" style="color:#f92672;">TABLE</span> <span class="hljs-string" style="color:#e6db74;">`model_test_person`</span> (<span class="hljs-string" style="color:#e6db74;">`id`</span> <span class="hljs-keyword" style="color:#f92672;">integer</span> AUTO_INCREMENT <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> <span class="hljs-keyword" style="color:#f92672;">PRIMARY</span> <span class="hljs-keyword" style="color:#f92672;">KEY</span>,<span class="hljs-string" style="color:#e6db74;">`name`</span> <span class="hljs-keyword" style="color:#f92672;">varchar</span>(<span class="hljs-number" style="color:#ae81ff;">30</span>) <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> ) ;</span> <span class="hljs-operator" style=""><span class="hljs-keyword" style="color:#f92672;margin-top:0px!important">CREATE</span> <span class="hljs-keyword" style="color:#f92672;">TABLE</span> <span class="hljs-string" style="color:#e6db74;">`model_test_group`</span> (<span class="hljs-string" style="color:#e6db74;">`id`</span> <span class="hljs-keyword" style="color:#f92672;">integer</span> AUTO_INCREMENT <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> <span class="hljs-keyword" style="color:#f92672;">PRIMARY</span> <span class="hljs-keyword" style="color:#f92672;">KEY</span>,<span class="hljs-string" style="color:#e6db74;">`name`</span> <span class="hljs-keyword" style="color:#f92672;">varchar</span>(<span class="hljs-number" style="color:#ae81ff;">30</span>) <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> ) ;</span> <span class="hljs-operator" style=""><span class="hljs-keyword" style="color:#f92672;margin-top:0px!important">CREATE</span> <span class="hljs-keyword" style="color:#f92672;">TABLE</span> <span class="hljs-string" style="color:#e6db74;">`model_test_membership`</span> (<span class="hljs-string" style="color:#e6db74;">`id`</span> <span class="hljs-keyword" style="color:#f92672;">integer</span> AUTO_INCREMENT <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> <span class="hljs-keyword" style="color:#f92672;">PRIMARY</span> <span class="hljs-keyword" style="color:#f92672;">KEY</span>,<span class="hljs-string" style="color:#e6db74;">`person_id`</span> <span class="hljs-keyword" style="color:#f92672;">integer</span> <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span>,<span class="hljs-string" style="color:#e6db74;">`group_id`</span> <span class="hljs-keyword" style="color:#f92672;">integer</span> <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span>,<span class="hljs-string" style="color:#e6db74;">`date_joined`</span> <span class="hljs-keyword" style="color:#f92672;">date</span> <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span>,<span class="hljs-string" style="color:#e6db74;">`invite_person`</span> <span class="hljs-keyword" style="color:#f92672;">varchar</span>(<span class="hljs-number" style="color:#ae81ff;">30</span>) <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> ) ;</span> <span class="hljs-operator" style=""><span class="hljs-keyword" style="color:#f92672;margin-top:0px!important">ALTER</span> <span class="hljs-keyword" style="color:#f92672;">TABLE</span> <span class="hljs-string" style="color:#e6db74;">`model_test_membership`</span> <span class="hljs-keyword" style="color:#f92672;">ADD</span> <span class="hljs-keyword" style="color:#f92672;">CONSTRAINT</span> <span class="hljs-string" style="color:#e6db74;">`group_id_refs_id_be33a6a7`</span> <span class="hljs-keyword" style="color:#f92672;">FOREIGN</span> <span class="hljs-keyword" style="color:#f92672;">KEY</span> (<span class="hljs-string" style="color:#e6db74;">`group_id`</span>) <span class="hljs-keyword" style="color:#f92672;">REFERENCES</span> <span class="hljs-string" style="color:#e6db74;">`model_test_group`</span> (<span class="hljs-string" style="color:#e6db74;">`id`</span>);</span> <span class="hljs-operator" style=""><span class="hljs-keyword" style="color:#f92672;margin-top:0px!important">ALTER</span> <span class="hljs-keyword" style="color:#f92672;">TABLE</span> <span class="hljs-string" style="color:#e6db74;">`model_test_membership`</span> <span class="hljs-keyword" style="color:#f92672;">ADD</span> <span class="hljs-keyword" style="color:#f92672;">CONSTRAINT</span> <span class="hljs-string" style="color:#e6db74;">`person_id_refs_id_90aaf3d5`</span> <span class="hljs-keyword" style="color:#f92672;">FOREIGN</span> <span class="hljs-keyword" style="color:#f92672;">KEY</span> (<span class="hljs-string" style="color:#e6db74;">`person_id`</span>) <span class="hljs-keyword" style="color:#f92672;">REFERENCES</span> <span class="hljs-string" style="color:#e6db74;">`model_test_person`</span> (<span class="hljs-string" style="color:#e6db74;">`id`</span>);</span> </code>對(duì)Model進(jìn)行增加/刪除操作:
<code class="hljs python" style="font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:undefined; padding:0.5em; color:rgb(248,248,242); background-color:rgb(35,36,31); display:block; margin-top:0px!important"><span class="hljs-prompt" style="color:#e6db74;margin-top:0px!important">>>> </span><span class="hljs-keyword" style="color:#f92672;">import</span> datetime <span class="hljs-prompt" style="color:#e6db74;">>>> </span><span class="hljs-keyword" style="color:#f92672;">from</span> model_test.models <span class="hljs-keyword" style="color:#f92672;">import</span> Person <span class="hljs-prompt" style="color:#e6db74;">>>> </span><span class="hljs-keyword" style="color:#f92672;">from</span> model_test.models <span class="hljs-keyword" style="color:#f92672;">import</span> Group <span class="hljs-prompt" style="color:#e6db74;">>>> </span><span class="hljs-keyword" style="color:#f92672;">from</span> model_test.models <span class="hljs-keyword" style="color:#f92672;">import</span> Membership <span class="hljs-prompt" style="color:#e6db74;">>>> </span> <span class="hljs-prompt" style="color:#e6db74;">>>> </span>suo = Person.objects.create(name=<span class="hljs-string" style="color:#e6db74;">"suo"</span>) <span class="hljs-prompt" style="color:#e6db74;">>>> </span>piao = Person.objects.create(name=<span class="hljs-string" style="color:#e6db74;">"piao"</span>) <span class="hljs-prompt" style="color:#e6db74;">>>> </span>english = Group.objects.create(name=<span class="hljs-string" style="color:#e6db74;">"English"</span>) <span class="hljs-prompt" style="color:#e6db74;">>>> </span> <span class="hljs-prompt" style="color:#e6db74;">>>> </span>m1 = Membership(person=suo, group=english, date_joined=datetime.date(<span class="hljs-number" style="color:#ae81ff;">2014</span>, <span class="hljs-number" style="color:#ae81ff;">9</span>, <span class="hljs-number" style="color:#ae81ff;">9</span>), invite_person=<span class="hljs-string" style="color:#e6db74;">"summer"</span>) <span class="hljs-prompt" style="color:#e6db74;">>>> </span>m1.save() <span class="hljs-prompt" style="color:#e6db74;">>>> </span>m2 = Membership.objects.create(person=piao, group=english, date_joined=datetime.date(<span class="hljs-number" style="color:#ae81ff;">2014</span>, <span class="hljs-number" style="color:#ae81ff;">8</span>, <span class="hljs-number" style="color:#ae81ff;">8</span>), invite_person=<span class="hljs-string" style="color:#e6db74;">"spring"</span>) <span class="hljs-prompt" style="color:#e6db74;">>>> </span> <span class="hljs-prompt" style="color:#e6db74;">>>> </span>english.members.all() [<Person: suo>, <Person: piao>] </code>注意,這種形式的多對(duì)多,添加兩個(gè)Model的關(guān)系時(shí),不能夠通過(guò)Model的關(guān)聯(lián)屬性直接添加,而應(yīng)該是創(chuàng)建中間關(guān)系的對(duì)象,即不能執(zhí)行這樣的操作:
<code style="font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:undefined; padding:0px; color:inherit; background-color:transparent; margin-top:0px!important">english.members.add(suo) </code>因?yàn)樘砑雨P(guān)系還有其他的屬性(date_jointed/invite_person)需要指定,所以不能夠直接添加。
一對(duì)一
一對(duì)一是通過(guò)django.db.models.OneToOneField來(lái)實(shí)現(xiàn)的,被關(guān)聯(lián)的Model會(huì)被加上Unique的限制。比如Person和IdCard就是一對(duì)一的關(guān)系,用Django的Model來(lái)表示,就是:
<code class="hljs python" style="font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:undefined; padding:0.5em; color:rgb(248,248,242); background-color:rgb(35,36,31); display:block; margin-top:0px!important"><span class="hljs-class" style="margin-top:0px!important"><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">class</span> <span class="hljs-title" style="">IdCard</span><span class="hljs-params" style="">(models.Model)</span>:</span>number = models.CharField(max_length=<span class="hljs-number" style="color:#ae81ff;">30</span>)person = models.OneToOneField(Person)<span class="hljs-class" style=""><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">class</span> <span class="hljs-title" style="">Person</span><span class="hljs-params" style="">(models.Model)</span>:</span>name = models.CharField(max_length=<span class="hljs-number" style="color:#ae81ff;">30</span>)<span class="hljs-function" style="color:#f92672;"><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">def</span> <span class="hljs-title" style="color:#a6e22e;">__unicode__</span><span class="hljs-params" style="color:#f8f8f2;">(self)</span>:</span><span class="hljs-keyword" style="color:#f92672;">return</span> self.name </code>對(duì)應(yīng)的SQL語(yǔ)句為:
<code class="hljs sql" style="font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:undefined; padding:0.5em; color:rgb(248,248,242); background-color:rgb(35,36,31); display:block; margin-top:0px!important"><span class="hljs-operator" style="margin-top:0px!important"><span class="hljs-keyword" style="color:#f92672;margin-top:0px!important">CREATE</span> <span class="hljs-keyword" style="color:#f92672;">TABLE</span> <span class="hljs-string" style="color:#e6db74;">`model_test_person`</span> (<span class="hljs-string" style="color:#e6db74;">`id`</span> <span class="hljs-keyword" style="color:#f92672;">integer</span> AUTO_INCREMENT <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> <span class="hljs-keyword" style="color:#f92672;">PRIMARY</span> <span class="hljs-keyword" style="color:#f92672;">KEY</span>,<span class="hljs-string" style="color:#e6db74;">`name`</span> <span class="hljs-keyword" style="color:#f92672;">varchar</span>(<span class="hljs-number" style="color:#ae81ff;">30</span>) <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> ) ;</span> <span class="hljs-operator" style=""><span class="hljs-keyword" style="color:#f92672;margin-top:0px!important">CREATE</span> <span class="hljs-keyword" style="color:#f92672;">TABLE</span> <span class="hljs-string" style="color:#e6db74;">`model_test_idcard`</span> (<span class="hljs-string" style="color:#e6db74;">`id`</span> <span class="hljs-keyword" style="color:#f92672;">integer</span> AUTO_INCREMENT <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> <span class="hljs-keyword" style="color:#f92672;">PRIMARY</span> <span class="hljs-keyword" style="color:#f92672;">KEY</span>,<span class="hljs-string" style="color:#e6db74;">`number`</span> <span class="hljs-keyword" style="color:#f92672;">varchar</span>(<span class="hljs-number" style="color:#ae81ff;">30</span>) <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span>,<span class="hljs-string" style="color:#e6db74;">`person_id`</span> <span class="hljs-keyword" style="color:#f92672;">integer</span> <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> <span class="hljs-keyword" style="color:#f92672;">UNIQUE</span> ) ;</span> <span class="hljs-operator" style=""><span class="hljs-keyword" style="color:#f92672;margin-top:0px!important">ALTER</span> <span class="hljs-keyword" style="color:#f92672;">TABLE</span> <span class="hljs-string" style="color:#e6db74;">`model_test_idcard`</span> <span class="hljs-keyword" style="color:#f92672;">ADD</span> <span class="hljs-keyword" style="color:#f92672;">CONSTRAINT</span> <span class="hljs-string" style="color:#e6db74;">`person_id_refs_id_c2c57084`</span> <span class="hljs-keyword" style="color:#f92672;">FOREIGN</span> <span class="hljs-keyword" style="color:#f92672;">KEY</span> (<span class="hljs-string" style="color:#e6db74;">`person_id`</span>) <span class="hljs-keyword" style="color:#f92672;">REFERENCES</span> <span class="hljs-string" style="color:#e6db74;">`model_test_person`</span> (<span class="hljs-string" style="color:#e6db74;">`id`</span>);</span> </code>注意model_test_idcard表的person_id加上了unique限制。
接下來(lái),再來(lái)介紹一下Model的繼承,有三種:Abstract base classes, Multi-table inheritance, Proxy models
Abstract base classes
Model之間的繼承關(guān)系其實(shí)也就是Python中的繼承,子類繼承父類中的屬性,但是由于每一個(gè)Model都對(duì)應(yīng)了數(shù)據(jù)庫(kù)中的一個(gè)數(shù)據(jù)表,所以有些地方得需要做一些特殊處理:做為父類的Model要在它的Meta中顯示的申明為抽象,否則也會(huì)為父類創(chuàng)建數(shù)據(jù)庫(kù)表,一般情況下,我們只需要父類做為一個(gè)存放公共代碼的地方,并不想要它有自己的數(shù)據(jù)庫(kù)表。需要注意的是,子類繼承父類中的屬性,包括Meta中的屬性,但是唯獨(dú)不繼承Meta中的abstract屬性,如果子類也想要是抽象Model,那么要顯示的再次指定該參數(shù)。如下面的例子:
<code class="hljs python" style="font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:undefined; padding:0.5em; color:rgb(248,248,242); background-color:rgb(35,36,31); display:block; margin-top:0px!important"><span class="hljs-class" style="margin-top:0px!important"><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">class</span> <span class="hljs-title" style="">CommonInfo</span><span class="hljs-params" style="">(models.Model)</span>:</span>name = models.CharField(max_length=<span class="hljs-number" style="color:#ae81ff;">30</span>)age = models.PositiveIntegerField()<span class="hljs-class" style=""><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">class</span> <span class="hljs-title" style="color:#a6e22e;font-style:italic">Meta</span>:</span>abstract = <span class="hljs-keyword" style="color:#f92672;">True</span><span class="hljs-class" style=""><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">class</span> <span class="hljs-title" style="">Student</span><span class="hljs-params" style="">(CommonInfo)</span>:</span>score = models.IntegerField()<span class="hljs-class" style=""><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">class</span> <span class="hljs-title" style="">Teacher</span><span class="hljs-params" style="">(CommonInfo)</span>:</span>rating = models.CharField(max_length=<span class="hljs-number" style="color:#ae81ff;">30</span>) </code>對(duì)應(yīng)的SQL語(yǔ)句為:
<code class="hljs sql" style="font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:undefined; padding:0.5em; color:rgb(248,248,242); background-color:rgb(35,36,31); display:block; margin-top:0px!important"><span class="hljs-operator" style="margin-top:0px!important"><span class="hljs-keyword" style="color:#f92672;margin-top:0px!important">CREATE</span> <span class="hljs-keyword" style="color:#f92672;">TABLE</span> <span class="hljs-string" style="color:#e6db74;">`model_test_student`</span> (<span class="hljs-string" style="color:#e6db74;">`id`</span> <span class="hljs-keyword" style="color:#f92672;">integer</span> AUTO_INCREMENT <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> <span class="hljs-keyword" style="color:#f92672;">PRIMARY</span> <span class="hljs-keyword" style="color:#f92672;">KEY</span>,<span class="hljs-string" style="color:#e6db74;">`name`</span> <span class="hljs-keyword" style="color:#f92672;">varchar</span>(<span class="hljs-number" style="color:#ae81ff;">30</span>) <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span>,<span class="hljs-string" style="color:#e6db74;">`age`</span> <span class="hljs-keyword" style="color:#f92672;">integer</span> UNSIGNED <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span>,<span class="hljs-string" style="color:#e6db74;">`score`</span> <span class="hljs-keyword" style="color:#f92672;">integer</span> <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> ) ;</span> <span class="hljs-operator" style=""><span class="hljs-keyword" style="color:#f92672;margin-top:0px!important">CREATE</span> <span class="hljs-keyword" style="color:#f92672;">TABLE</span> <span class="hljs-string" style="color:#e6db74;">`model_test_teacher`</span> (<span class="hljs-string" style="color:#e6db74;">`id`</span> <span class="hljs-keyword" style="color:#f92672;">integer</span> AUTO_INCREMENT <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> <span class="hljs-keyword" style="color:#f92672;">PRIMARY</span> <span class="hljs-keyword" style="color:#f92672;">KEY</span>,<span class="hljs-string" style="color:#e6db74;">`name`</span> <span class="hljs-keyword" style="color:#f92672;">varchar</span>(<span class="hljs-number" style="color:#ae81ff;">30</span>) <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span>,<span class="hljs-string" style="color:#e6db74;">`age`</span> <span class="hljs-keyword" style="color:#f92672;">integer</span> UNSIGNED <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span>,<span class="hljs-string" style="color:#e6db74;">`rating`</span> <span class="hljs-keyword" style="color:#f92672;">varchar</span>(<span class="hljs-number" style="color:#ae81ff;">30</span>) <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> ) ;</span> </code>Multi-table inheritance
這種和上面的區(qū)別就是把父類中的Meta的abstract去掉了,也就是說(shuō)父類也有自己的數(shù)據(jù)庫(kù)表,而且這個(gè)父類和子類之間是一對(duì)一的關(guān)系。例子如下:
<code class="hljs python" style="font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:undefined; padding:0.5em; color:rgb(248,248,242); background-color:rgb(35,36,31); display:block; margin-top:0px!important"><span class="hljs-class" style="margin-top:0px!important"><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">class</span> <span class="hljs-title" style="">Place</span><span class="hljs-params" style="">(models.Model)</span>:</span>name = models.CharField(max_length=<span class="hljs-number" style="color:#ae81ff;">30</span>)address = models.CharField(max_length=<span class="hljs-number" style="color:#ae81ff;">30</span>)<span class="hljs-function" style="color:#f92672;"><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">def</span> <span class="hljs-title" style="color:#a6e22e;">__unicode__</span><span class="hljs-params" style="color:#f8f8f2;">(self)</span>:</span><span class="hljs-keyword" style="color:#f92672;">return</span> self.name<span class="hljs-class" style=""><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">class</span> <span class="hljs-title" style="">Restaurant</span><span class="hljs-params" style="">(Place)</span>:</span>serves_hot_dogs = models.BooleanField()serves_pizza = models.BooleanField() </code>得到的SQL如下:
<code class="hljs sql" style="font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:undefined; padding:0.5em; color:rgb(248,248,242); background-color:rgb(35,36,31); display:block; margin-top:0px!important"><span class="hljs-operator" style="margin-top:0px!important"><span class="hljs-keyword" style="color:#f92672;margin-top:0px!important">CREATE</span> <span class="hljs-keyword" style="color:#f92672;">TABLE</span> <span class="hljs-string" style="color:#e6db74;">`model_test_place`</span> (<span class="hljs-string" style="color:#e6db74;">`id`</span> <span class="hljs-keyword" style="color:#f92672;">integer</span> AUTO_INCREMENT <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> <span class="hljs-keyword" style="color:#f92672;">PRIMARY</span> <span class="hljs-keyword" style="color:#f92672;">KEY</span>,<span class="hljs-string" style="color:#e6db74;">`name`</span> <span class="hljs-keyword" style="color:#f92672;">varchar</span>(<span class="hljs-number" style="color:#ae81ff;">30</span>) <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span>,<span class="hljs-string" style="color:#e6db74;">`address`</span> <span class="hljs-keyword" style="color:#f92672;">varchar</span>(<span class="hljs-number" style="color:#ae81ff;">30</span>) <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> ) ;</span> <span class="hljs-operator" style=""><span class="hljs-keyword" style="color:#f92672;margin-top:0px!important">CREATE</span> <span class="hljs-keyword" style="color:#f92672;">TABLE</span> <span class="hljs-string" style="color:#e6db74;">`model_test_restaurant`</span> (<span class="hljs-string" style="color:#e6db74;">`place_ptr_id`</span> <span class="hljs-keyword" style="color:#f92672;">integer</span> <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> <span class="hljs-keyword" style="color:#f92672;">PRIMARY</span> <span class="hljs-keyword" style="color:#f92672;">KEY</span>,<span class="hljs-string" style="color:#e6db74;">`serves_hot_dogs`</span> bool <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span>,<span class="hljs-string" style="color:#e6db74;">`serves_pizza`</span> bool <span class="hljs-keyword" style="color:#f92672;">NOT</span> <span class="hljs-keyword" style="color:#f92672;">NULL</span> ) ;</span> <span class="hljs-operator" style=""><span class="hljs-keyword" style="color:#f92672;margin-top:0px!important">ALTER</span> <span class="hljs-keyword" style="color:#f92672;">TABLE</span> <span class="hljs-string" style="color:#e6db74;">`model_test_restaurant`</span> <span class="hljs-keyword" style="color:#f92672;">ADD</span> <span class="hljs-keyword" style="color:#f92672;">CONSTRAINT</span> <span class="hljs-string" style="color:#e6db74;">`place_ptr_id_refs_id_cc7b5838`</span> <span class="hljs-keyword" style="color:#f92672;">FOREIGN</span> <span class="hljs-keyword" style="color:#f92672;">KEY</span> (<span class="hljs-string" style="color:#e6db74;">`place_ptr_id`</span>) <span class="hljs-keyword" style="color:#f92672;">REFERENCES</span> <span class="hljs-string" style="color:#e6db74;">`model_test_place`</span> (<span class="hljs-string" style="color:#e6db74;">`id`</span>);</span> </code>添加一個(gè)Place很容易,那么怎么來(lái)添加一個(gè)Restaurant呢?而且兩者是一對(duì)一的關(guān)系,怎么來(lái)添加他們之間的關(guān)系呢?記住,Restaurant是Place的子類,繼承了Place的屬性,所以直接創(chuàng)建Restaurant就可以了:
<code class="hljs python" style="font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:undefined; padding:0.5em; color:rgb(248,248,242); background-color:rgb(35,36,31); display:block; margin-top:0px!important"><span class="hljs-prompt" style="color:#e6db74;margin-top:0px!important">>>> </span><span class="hljs-keyword" style="color:#f92672;">from</span> model_test.models <span class="hljs-keyword" style="color:#f92672;">import</span> Restaurant <span class="hljs-prompt" style="color:#e6db74;">>>> </span>Restaurant.objects.create(name=<span class="hljs-string" style="color:#e6db74;">"r1"</span>, address=<span class="hljs-string" style="color:#e6db74;">"a1"</span>, serves_hot_dogs=<span class="hljs-keyword" style="color:#f92672;">True</span>, serves_pizza=<span class="hljs-keyword" style="color:#f92672;">False</span>) <Restaurant: r1> </code>這樣,在數(shù)據(jù)庫(kù)中,就會(huì)分別向place和restaurant表中各添加一條記錄,而且restaurant表中用place id作為主鍵。
更多關(guān)于這個(gè)類型的內(nèi)容見:Multi-table inheritance
Proxy models
這種類型的繼承用的比較少,它主要用來(lái)在不改變?cè)瓉?lái)Model的行為的情況下,擴(kuò)展Model的行為,即為原來(lái)的Model設(shè)置了一個(gè)代理,可以重新定義該代理的行為,但是保留原來(lái)Model的行為。比如說(shuō)原來(lái)的Model我想讓它是一種排序方法,但是我也想讓它有另外一種排序方法怎么辦?那就為該Model創(chuàng)建一個(gè)代理,在這個(gè)代理中指定另外一個(gè)排序方法,通過(guò)這個(gè)代理來(lái)訪問(wèn),就可以得到新的排序。
這里有個(gè)限制,就是父Model不能是抽象的。舉個(gè)例子:
<code class="hljs python" style="font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:undefined; padding:0.5em; color:rgb(248,248,242); background-color:rgb(35,36,31); display:block; margin-top:0px!important"><span class="hljs-class" style="margin-top:0px!important"><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">class</span> <span class="hljs-title" style="">Person</span><span class="hljs-params" style="">(models.Model)</span>:</span>first_name = models.CharField(max_length=<span class="hljs-number" style="color:#ae81ff;">30</span>)last_name = models.CharField(max_length=<span class="hljs-number" style="color:#ae81ff;">30</span>)<span class="hljs-class" style=""><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">class</span> <span class="hljs-title" style="color:#a6e22e;font-style:italic">Meta</span>:</span>ordering = [<span class="hljs-string" style="color:#e6db74;">'first_name'</span>]<span class="hljs-function" style="color:#f92672;"><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">def</span> <span class="hljs-title" style="color:#a6e22e;">__unicode__</span><span class="hljs-params" style="color:#f8f8f2;">(self)</span>:</span><span class="hljs-keyword" style="color:#f92672;">return</span> self.name<span class="hljs-class" style=""><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">class</span> <span class="hljs-title" style="">MyPerson</span><span class="hljs-params" style="">(Person)</span>:</span><span class="hljs-class" style=""><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">class</span> <span class="hljs-title" style="color:#a6e22e;font-style:italic">Meta</span>:</span>proxy = <span class="hljs-keyword" style="color:#f92672;">True</span>ordering = [<span class="hljs-string" style="color:#e6db74;">'last_name'</span>]<span class="hljs-function" style="color:#f92672;"><span class="hljs-keyword" style="color:#66d9ef;margin-top:0px!important">def</span> <span class="hljs-title" style="color:#a6e22e;">do_something</span><span class="hljs-params" style="color:#f8f8f2;">(self)</span>:</span><span class="hljs-keyword" style="color:#f92672;">pass</span> </code>在子類中的Meta中設(shè)置了proxy=True,就是指定該Model為代理Model,他們兩個(gè)對(duì)應(yīng)同一個(gè)數(shù)據(jù)庫(kù),但是有不同的訪問(wèn)行為。通過(guò)MyPerson訪問(wèn)的數(shù)據(jù),會(huì)按last_name進(jìn)行排序,而且還可以通過(guò)定義新的方法,擴(kuò)展它的功能。如:
<code class="hljs python" style="font-family:Menlo,Monaco,Consolas,'Courier New',monospace;font-size:undefined; padding:0.5em; color:rgb(248,248,242); background-color:rgb(35,36,31); display:block; margin-top:0px!important"><span class="hljs-prompt" style="color:#e6db74;margin-top:0px!important">>>> </span><span class="hljs-keyword" style="color:#f92672;">from</span> model_test.models <span class="hljs-keyword" style="color:#f92672;">import</span> Person <span class="hljs-prompt" style="color:#e6db74;">>>> </span><span class="hljs-keyword" style="color:#f92672;">from</span> model_test.models <span class="hljs-keyword" style="color:#f92672;">import</span> MyPerson<span class="hljs-prompt" style="color:#e6db74;">>>> </span>Person.objects.create(first_name=<span class="hljs-string" style="color:#e6db74;">"suo"</span>, last_name=<span class="hljs-string" style="color:#e6db74;">"guangyu"</span>) <Person: suo guangyu> <span class="hljs-prompt" style="color:#e6db74;">>>> </span>Person.objects.create(first_name=<span class="hljs-string" style="color:#e6db74;">"xing"</span>, last_name=<span class="hljs-string" style="color:#e6db74;">"demo"</span>) <Person: xing demo><span class="hljs-prompt" style="color:#e6db74;">>>> </span>Person.objects.all() [<Person: suo guangyu>, <Person: xing demo>] <span class="hljs-prompt" style="color:#e6db74;">>>> </span>MyPerson.objects.all() [<MyPerson: xing demo>, <MyPerson: suo guangyu>] >>> </code>這個(gè)類型的繼承還是很有用的。
總結(jié)
以上是生活随笔為你收集整理的Django学习小记[2] —— Model的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 用 GRUB 引导自己的操作系统
- 下一篇: 实模式和保护模式区别及寻址方式