Django学习小记[2] —— Model
開始學習django的model了,學習django的目的很簡單,就是我想用django搭建一個自己的博客,現在開源的已經有django-zinnia這個博客引擎了,但是想要看懂它,并且修改它,就必須過django這一關。之前對django的了解,僅僅限于用到了什么,就知道什么,缺乏系統的學習,所以要把django的文檔都過一遍,做一下簡單的筆記。
今天的主題是Model,Model就是MVC中的M,代表的數據對象,反映到數據庫中就是數據表,Model中的屬性是表的一列,Django對Model進行了封裝,對Model提供了豐富的查詢接口,反映到數據庫中,就是提供了豐富的select查詢功能,這就是Django的強大之處。
先來看一個簡單的例子,在一個app中的models.py中,定義一個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類的每一個屬性都繼承自django.db.models.Field,這個Field有幾個作用:
- 決定該Field在數據庫中的類型
- 決定該Field在前端上如何顯示
- 做簡單的驗證
Django有很多內置的Field,當然也可以自定義。
好,下面我們來重點說一下在Django中如何實現關系型數據庫的那三種典型關系:多對一,多對多,一對一
多對一
實現多對一,是使用django.db.models.ForeignKey類,ForeignKey需要一個positional的參數來指定本Model關聯的Model,ForeignKey關聯的Model是“一”,ForeignKey所在的Model是“多”,比如汽車和制造商的例子,一個汽車只能屬于一個制造商,但是一個制造商有多個汽車,這個關系,用Django的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-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>該關系,用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_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>關于多對一更多的內容,參考:Many-to-One
多對多
要實現多對多,就要使用django.db.models.ManyToManyField類,和ForeignKey一樣,它也有一個positional的參數,用來指定和它關聯的Model。
如果不僅僅需要知道兩個Model之間是多對多的關系,還需要知道這個關系的更多信息,比如Person和Group是多對多的關系,除了知道一個Person屬于哪個Group之外,如果還想知道這個Person是什么時候加入這個Group的,那么就需要有一個中間表來記錄這些信息,那就用到了ManyToManyFiled的一個optional參數: 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>在中間表中,通過外鍵關聯到Person和Group,其實,就是兩個多對一的關系,上面對應的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_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>對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-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>注意,這種形式的多對多,添加兩個Model的關系時,不能夠通過Model的關聯屬性直接添加,而應該是創建中間關系的對象,即不能執行這樣的操作:
<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>因為添加關系還有其他的屬性(date_jointed/invite_person)需要指定,所以不能夠直接添加。
一對一
一對一是通過django.db.models.OneToOneField來實現的,被關聯的Model會被加上Unique的限制。比如Person和IdCard就是一對一的關系,用Django的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-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>對應的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_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限制。
接下來,再來介紹一下Model的繼承,有三種:Abstract base classes, Multi-table inheritance, Proxy models
Abstract base classes
Model之間的繼承關系其實也就是Python中的繼承,子類繼承父類中的屬性,但是由于每一個Model都對應了數據庫中的一個數據表,所以有些地方得需要做一些特殊處理:做為父類的Model要在它的Meta中顯示的申明為抽象,否則也會為父類創建數據庫表,一般情況下,我們只需要父類做為一個存放公共代碼的地方,并不想要它有自己的數據庫表。需要注意的是,子類繼承父類中的屬性,包括Meta中的屬性,但是唯獨不繼承Meta中的abstract屬性,如果子類也想要是抽象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-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>對應的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_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
這種和上面的區別就是把父類中的Meta的abstract去掉了,也就是說父類也有自己的數據庫表,而且這個父類和子類之間是一對一的關系。例子如下:
<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>添加一個Place很容易,那么怎么來添加一個Restaurant呢?而且兩者是一對一的關系,怎么來添加他們之間的關系呢?記住,Restaurant是Place的子類,繼承了Place的屬性,所以直接創建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>這樣,在數據庫中,就會分別向place和restaurant表中各添加一條記錄,而且restaurant表中用place id作為主鍵。
更多關于這個類型的內容見:Multi-table inheritance
Proxy models
這種類型的繼承用的比較少,它主要用來在不改變原來Model的行為的情況下,擴展Model的行為,即為原來的Model設置了一個代理,可以重新定義該代理的行為,但是保留原來Model的行為。比如說原來的Model我想讓它是一種排序方法,但是我也想讓它有另外一種排序方法怎么辦?那就為該Model創建一個代理,在這個代理中指定另外一個排序方法,通過這個代理來訪問,就可以得到新的排序。
這里有個限制,就是父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-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中設置了proxy=True,就是指定該Model為代理Model,他們兩個對應同一個數據庫,但是有不同的訪問行為。通過MyPerson訪問的數據,會按last_name進行排序,而且還可以通過定義新的方法,擴展它的功能。如:
<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>這個類型的繼承還是很有用的。
總結
以上是生活随笔為你收集整理的Django学习小记[2] —— Model的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用 GRUB 引导自己的操作系统
- 下一篇: 实模式和保护模式区别及寻址方式