开始学习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相关推荐

  1. Django学习小记[3] —— Query

    今天学习的是Django的Model Query,前一篇已经学习过Model了,讲述的主要是Django中是如何处理关系型数据的模型的,一对一,多对一,多对多等,这篇则主要是描述的查询,能够将数据存进 ...

  2. Django介绍和虚拟环境(django特点、MVC、MVT、Django学习资料)

    MVT流程: 创建Django项目和应用 django-admin startproject name python manager.py startapp name 视图和ULR 视图的请求和响应 ...

  3. django 学习笔记

    django 学习笔记 启动虚拟机: workon bj18_py3 创建一个项目: django-admin.py startproject mysite 启动开发用服务器:从外层项目 mysite ...

  4. Django学习总结①

    Django学习总结① Django基础环境配置好以后,打开pycharm,创建Django项目 视图views 中需要导入 django.http ---> HttpResponsemodel ...

  5. django学习笔记01

    原创博客地址:django学习笔记01 基于教程,刘江的博客教程Django教程:https://www.liujiangblog.com/course/django/87 第一章:模型层 1.1 模 ...

  6. 自学python顺序-Django 学习顺序及入门要求?

    没有web开发经验和相关背景. 有c语言基础和python语法基础. 在进行django学习之前,还有哪些基础要求? django的学习顺序是什么? 时间较紧张,做一次自己一向鄙视的伸手党.抱歉抱歉. ...

  7. 千锋Django学习笔记

    千锋Django学习笔记 文章目录 千锋Django学习笔记 写在前面 1. MVC和MTV 2. Django简介 3. MTV简单流程 4. 和Model的简单对接 5. Model 6. Tem ...

  8. Python Django 学习 (二) 【Django 模型】

    注: 由于自己排版确实很难看,本文开始使用markdown编辑,希望有所改善 官方定义 A model is the single, definitive source of information ...

  9. Django 学习小组:博客开发实战第二周教程 —— 实现博客详情页面和分类页面

    本教程内容已过时,更新版教程请访问: django 博客开发入门教程. 上周我们完成了博客的 Model 部分,以及 Blog 的首页视图 IndexView. 本节接上周的文档 Django 学习小 ...

最新文章

  1. 高并发的核心技术 - 幂等的实现方案
  2. myeclipse2014新感悟
  3. NOIP 2017 d2t2 70points
  4. HDU-1212 Big Number JAVA又出毛病了
  5. torch 的 unsqueeze用法
  6. java注解如何设置自增长_java如何自定义注解(一)
  7. spring cloud: 使用consul来替换config server
  8. c++学习笔记之基础---类内声明线程函数的调用
  9. 将Spring集成到旧版应用程序中
  10. 恣无忌惮的拼音及解释
  11. 如何理解数列极限和收敛性
  12. 全面解析用友网络四位一体数字营销
  13. 百度统计接口调用——登录接口
  14. excel基础操作-数据有效性和条件格式
  15. 【EI会议分享】2022年第三届智能制造与自动化前沿国际会议(CFIMA 2022)
  16. Unity导表工具Luban插件的数据加载原理与优化
  17. linux图片格式转换工具,在Linux系统上安装和使用Converseen批量图像转换器的方法...
  18. ubuntu挂载4T新硬盘记录
  19. 电视剧名校分集剧情介绍二
  20. 计算机领域cip是什么意思,版权页上的CIP数据是什么意思?

热门文章

  1. 简单工厂模式、工厂方法模式、抽象工厂模式 之间的对比
  2. 【数字信号处理】相关函数应用 ( TDOA 时差估计 | 时间差与距离差 | 方向定位与精准定位 | 信号描述 | 通过相关函数求时间差 )
  3. 【Android 应用开发】Android应用的自动更新模块
  4. 理解面向对象编写的极致简单的小代码
  5. [题解] 2019牛客暑期多校第三场H题 Magic Line
  6. Intellij idea workflow 工作流插件安装
  7. 鼠标位置精确定位总结
  8. the more wites of color
  9. winFrom简单引用Webservice
  10. 采用Huffman编码进行数据压缩