标签:中间 dmi 基本 port rem harris tom 通用 wan
模型是数据信息的唯一并明确的来源。它包含了我们储存的数据的基本字段和行为。通常,每个模型映射到一张数据库表。
基本概念:
简单示例
下面的示例模型定义了一个Person,其拥有一个first_name和一个last_name属性。
from django.db import models class Person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30)
first_name和last_name是模型(model)的字段(fields).每个字段指定为类的一个属性,每个属性映射到数据库的一列(column)。
上面的Person模型将建立类似下面这样一个数据库:
CREATE TABLE myapp_person ( "id" serial NOT NULL primary_key, "first_name" varchar(30) NOT NULL, "last_name" varchar(30) NOT NULL );
关于上面代码的一些技术注释:
一旦定义好模型之后,需要告诉Django我们将使用这些模型。方法是通过编辑setting.py文件,在INSTALLED_APPS设定中添加包含了我们models.py的模块的名称。
例如,如果我们应用程序的模型存放在myapp.models模块中(该包结构在通过manage.py startapp命令创建应用程序时形成的),INSTALLED_APP应该一部分看起来如下:
INSTALLED_APPS = [ #... ‘myapp‘, #... ]
当添加apps到INSTALLED_APPS以后,确保要运行mangae.py migrate指令,有时候还需要先用manage.py makemigrations进行迁移。
字段(Fields)
一个模型最重要也是唯一要求的部门,就是定义数据库的字段。字段是由类的属性指定的。注意不要选择与模型API冲突的字段名,如clean,save或者delete等。
示例:
from django.db import models class Musician(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) instrument = models.CharField(max_length=100) class Album(models.Model): artist = models.ForeignKey(Musician, on_delete=models.CASCADE) name = models.CharField(max_length=100) release_date = models.DateField() num_stars = models.IntegerField()
Each field in your model should be an instance of the appropriate Field
class. Django uses the field class types to determine a few things:
模型的每一个字段都是相应字段类的一个实例。Django用字段类的类型来决定一些东西:
Django拥有许多内置的字段类型;完整的清单参见model field reference。如果内置的字段满足不了要求,我们也可以方便的编写自己的字段,具体参见Writing custom model fields。
字段选项(Field options)
每个字段都有一些特定的参数(参见 model field reference),例如,CharField(及其子类)要求一个最大长度参数来规定数据库VARCHAR字段的大小。
也有一些每种字段都通用的参数,都是可选的。在reference中有完整的解释,这里对最常用的一些做个快速的概览:
null
如果值为True,在数据库中Django将把空值储存为Null。默认值为False。
blank
如果值为True,字段允许为空。默认值为False。
注意它与null是不同的。null是纯粹数据库相关的,而blank是验证相关的。如果一个字段设置了blank=True, 表单验证将允许输入空值。如果设置了blank=False,该字段则是必需的。
choices
一个包含了二维元祖的可迭代对象(比如,列表或者元祖)作为字段的选项,默认的表单部件将从标准的文本换成选择框,选项限定为choice参数。
chiices列表看起来像这样:
YEAR_IN_SCHOOL_CHOICES = ( (‘FR‘, ‘Freshman‘), (‘SO‘, ‘Sophomore‘), (‘JR‘, ‘Junior‘), (‘SR‘, ‘Senior‘), (‘GR‘, ‘Graduate‘), )
每个元祖中的第一个元素是将储存在数据库中的值。第二个元素将通过默认的表单部件显示,或者放在ModelChoiceField中。给出一个模型实例,可以通过get_FOO_display()方法来访问choices field正在显示的值。
示例:
from django.db import models class Person(models.Model): SHIRT_SIZES = ( (‘S‘, ‘Small‘), (‘M‘, ‘Medium‘), (‘L‘, ‘Large‘), ) name = models.CharField(max_length=60) shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES) >>> p = Person(name="Fred Flintstone", shirt_size="L") >>> p.save() >>> p.shirt_size ‘L‘ >>> p.get_shirt_size_display() ‘Large‘
from django.db import models class Fruit(models.Model): name = models.CharField(max_length=100, primary_key=True) >>> fruit = Fruit.objects.create(name=‘Apple‘) >>> fruit.name = ‘Pear‘ >>> fruit.save() >>> Fruit.objects.values_list(‘name‘, flat=True) <QuerySet [‘Apple‘, ‘Pear‘]>
unique
id = models.AutoField(primary_key=True)
这是一个自动增长的主键。
如果你想指定一个自定义的主键,只要将某个字段的选项设置primary_key=True。如果Django发现你已经明确了字段的主键(Field.primary_key),它就不会再添加自动的id列。
每个模型要求必须有一个字段设定为primary_key=True(明确指定的或者自动添加的都可以)。
除ForeignKey, ManyToManyField 和 OneToOneField以外,每种字段都有一个第一位置参数-详细名称。如果该详细名称没有给出,Django会自动把字段的属性名称(下划线替换成空格)作为详细名称。
下面这个例子,详细名称是"person‘s first name":
first_name = models.CharField("person‘s first name", max_length=30)
下面这个例子,详细名称是"first name":
first_name = models.CharField(max_length=30)
ForeignKey, ManyToManyField 和 OneToOneField 要求第一位置参数为模型类,所以使用verbose_name关键字属性:
poll = models.ForeignKey( Poll, on_delete=models.CASCADE, verbose_name="the related poll", ) sites = models.ManyToManyField(Site, verbose_name="list of sites") place = models.OneToOneField( Place, on_delete=models.CASCADE, verbose_name="related place", )
有个惯例是不要将verbose_name的首字母大写,Django会再需要的时候自动将其首字母大写。
很明显,关系型数据库的能力来源于相互关联的表。Django提供了方法定义三种最常见的数据库关系:many-to-one, many-to-many and one-to-one。
通过django.db.models.ForeignKey来定义一对多关系。我们可以像使用其他字段类型一样:将其作为类属性包含在我们的模型中。
外键(ForeignKey)要求一个位置参数:该模型关联到哪个类。
比如,一个厂家制造了很多汽车,但是每辆汽车只有一个厂家,可以如下定义:
from django.db import models class Manufacturer(models.Model): # ... pass class Car(models.Model): manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE) # ...
你也可以创建一个递归关系recursive relationships(一个对象有一个指向自身的外键)以及与尚未定义的模型的关系relationships to models not yet defined,具体参见he model field reference。
建议,但没规定,将关联模型的小写名称作为外键字段的名称(上一个示例中的manufacturer)。当然,你可以叫外键字段任何名字,比如{
class Car(models.Model): company_that_makes_it = models.ForeignKey( Manufacturer, on_delete=models.CASCADE, ) # ...
参考信息
外键字段接收多种其他参数,具体参见the model field reference。这些选项帮助定义关系怎么工作,都是可选的。
关于访问向后相关(backwards-related)对象的细节,参见Following relationships backward example。
关于示例代码,参见Many-to-one relationship model example。
要定义一个多对多关系,用MangToManyField。
我们可以像使用其他字段类型一样:将其作为类属性包含在我们的模型中。
MangToManyField要求一个位置参数:该模型关联到哪个类。
比如,一个披萨有多种配料,一种配料也可以用在多个披萨上。可以这样描述:
from django.db import models class Topping(models.Model): # ... pass class Pizza(models.Model): # ... toppings = models.ManyToManyField(Topping)
当你只需要处理简单的多对多关系时,比如混合搭配披萨和配料,标准的多对多字段就够了。然而,有时候你需要两个模型之间关系的辅助数据。
例如,设想有一种程序用来追踪音乐家属于哪个乐队。人和乐队之间是一种多对多的关系,所以我们可以用一个多对多字段来描述该关系。然而,还有很多其他相关信息我们也想收集,比如某人加入某个乐队的日期。
针对这种情况,Django允许我们指定模型,用来管理该多对多关系。这样我们可以在中间模型中设置额外的字段。通过设置through参数来指出哪个模型作为媒介,将中间模型与多对多字段联合起来。我们的乐队示例,代码应该差不多像这样:
from django.db import models class Person(models.Model): name = models.CharField(max_length=128) def __str__(self): # __unicode__ on Python 2 return self.name class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through=‘Membership‘) def __str__(self): # __unicode__ on Python 2 return self.name class Membership(models.Model): person = models.ForeignKey(Person, on_delete=models.CASCADE) group = models.ForeignKey(Group, on_delete=models.CASCADE) date_joined = models.DateField() invite_reason = models.CharField(max_length=64)
当我们建立中间模型时,我们明确指定了到该多对多关系相关模型的外键。此明确声明定义了这两个模型时怎么关联的。
中间模型中有一些约束:
ManyToManyField.through_fields。如果有超过一个外键而且没有指定through_fields,会引发验证错误。到目标模型(我们示例中的Person)的外键也有同样的限制。
symmetrical=False
(参照 the model field reference)。现在我们已经设置好ManyToMany字段来使用我们的中间模型(示例中的Membership),已为建立一些多对多关系做好准备。可以通过创建中间模型的实例来实行:
>>> ringo = Person.objects.create(name="Ringo Starr") >>> paul = Person.objects.create(name="Paul McCartney") >>> beatles = Group.objects.create(name="The Beatles") >>> m1 = Membership(person=ringo, group=beatles, ... date_joined=date(1962, 8, 16), ... invite_reason="Needed a new drummer.") >>> m1.save() >>> beatles.members.all() <QuerySet [<Person: Ringo Starr>]> >>> ringo.group_set.all() <QuerySet [<Group: The Beatles>]> >>> m2 = Membership.objects.create(person=paul, group=beatles, ... date_joined=date(1960, 8, 1), ... invite_reason="Wanted to form a band.") >>> beatles.members.all() <QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>]>
不像普通的多对多字段,我们不可以用add(), create(), 或者 set() 去创建关系:
>>> # The following statements will not work >>> beatles.members.add(john) >>> beatles.members.create(name="George Harrison") >>> beatles.members.set([john, paul, ringo, george])
为什么?我们不能只创建人和乐队之间的关系,我们还需要指定Membership模型要求的关系的所有信息。简单的add, create无法指定额外的信息。所以,运用中间模型的多对多关系是禁用它们的。创建这种类型关系的唯一方法是创建中间模型的实例。
出于类似的原因, remove()方法也被禁用了。因为有时候remove()方法无法提供足够的信息来确认该删除哪一个中间模型实例:
>>> Membership.objects.create(person=ringo, group=beatles, ... date_joined=date(1968, 9, 4), ... invite_reason="You‘ve been gone for a month and we miss you.") >>> beatles.members.all() <QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>, <Person: Ringo Starr>]> >>> # This will not work because it cannot tell which membership to remove >>> beatles.members.remove(ringo)
然而,clear()方法可以删除一个实例的所有多对多关系:
>>> # Beatles have broken up >>> beatles.members.clear() >>> # Note that this deletes the intermediate model instances >>> Membership.objects.all() <QuerySet []>
一旦通过创建中间模型实例建立了多对多关系,我们就可以进行查询了。就像普通多对多关系一样,我们可以通过相关模型的属性进行查询:
# Find all the groups with a member whose name starts with ‘Paul‘ >>> Group.objects.filter(members__name__startswith=‘Paul‘) <QuerySet [<Group: The Beatles>]>
也可以通过中间模型的属性进行查询:
# Find all the members of the Beatles that joined after 1 Jan 1961 >>> Person.objects.filter( ... group__name=‘The Beatles‘, ... membership__date_joined__gt=date(1961,1,1)) <QuerySet [<Person: Ringo Starr]>
如果需要访问中间模型的信息,我们可以直接对中间模型进行查询:
>>> ringos_membership = Membership.objects.get(group=beatles, person=ringo) >>> ringos_membership.date_joined datetime.date(1962, 8, 16) >>> ringos_membership.invite_reason ‘Needed a new drummer.‘
另一种访问相同信息的方法是从Person对象查询many-to-many reverse relationship:
>>> ringos_membership = ringo.membership_set.get(group=beatles) >>> ringos_membership.date_joined datetime.date(1962, 8, 16) >>> ringos_membership.invite_reason ‘Needed a new drummer.‘
用OneToOneField定义一对一关系。像任何其他字段类型一样使用:作为属性包含在模型中。
如果一个对象继承自其他对象,一对一关系最适合用于它的主键。
OneToOneField要求一个位置参数:哪个模型是相关的。
例如,我们要建立一个关于“处所”的数据库,可能要在数据库中建立很多标准的东西,如地址、电话号码等。这时,如果你还想在这些处所的基础上再建立一个餐厅的数据库,不必在餐厅模型中再重复指定这些字段,只需要在餐厅模型中建立一个指向处所模型的一对一字段。(因为一间餐厅也是一个处所。实际上,这种情况我们通常使用继承inheritance,它是毫无疑问的一对一关系。)
跟外键一样,你也可以创建递归关系以及与尚未定义的模型的关系。
参考信息
完整实例请参见One-to-one relationship model example 。
一对一字段也接收一个可选的 parent_link
参数。
一对一字段类以前会自动成为模型的主键,现在不是这样了(尽管可以手动设置primary_key参数,如果我们想的话)。因此,现在同一个模型中可以有多个一对一字段。
标签:中间 dmi 基本 port rem harris tom 通用 wan
原文地址:http://www.cnblogs.com/dreamkeeper/p/7623894.html