Django model 关系映射

1.3.5.1. 多对一关系

要定义一个多对一关系,请使用ForeignKey。ForeignKey的用法和其它字段类型一样:把它包含在你的模型的类属性中。

ForeignKey需要一个位置参数:该模型相关的类。

例如,如果Car模型有一个Manufacturer,一个Manufacturer制造多辆汽车,但每个Car只有一个Manufacturer,那么应该定义如下:

(笔记:文章和分类的关系就是多对一关系)

class Manufacturer(models.Model):
    #...
class Car(models.Model):
    manufacturer = models.ForeignKey(Manufacturer)
    #...

你也可以创建循环关系(一个带有到自己的多对一关系的对象)和到未定义的模型的关系;详情请参阅“模型字段参考(URL)”。

建议但不强制要求ForeignKey字段的名字是模型的小写字母的名字(例如在上例中使用的manufacturer)。当然你可以使用任何你想要的名字,例如:

class Car(models.Model):
    company_that_makes_it = models.ForeignKey(Manufacturer)
    #...

参阅“多对一关系模型的例子(URL)”来看一下完整的例子。

ForeignKey字段也接受一些额外的参数,可以参阅“模型字段参考(URL)”。这些选项帮助你定义关系的工作方式,不过它们都是可选的。

1.3.5.2. 多对多关系

要定义多对多关系,请使用ManyToManyField。它的使用方法和其它字段类型一样:把它包含在你的模型的类属性中。

ManyToManyField要求一个位置参数:该模型相关的类。

例如,一个Pizza有多个Topping对象——也就是一个Topping可以在多个比萨上,每个Pizza有多个Toppings——这种情况我们可以这样定义:

(笔记:文章和标签的关系就是多对多关系)

class Topping(models.Model):
    #...
class Pizza(models.Model):
    #...
    toppings = models.ManyToManyField(Topping)

和Foreign一样,你也可以创建循环关系(带有到自己的多对多关系的对象)和到未定义模型的关系;详情参阅“模型字段参考(URL)”。

建议但不强制要求ManyToManyField的名字(上面的例子中的toppings)是复数形式,复数形式是为了描述相关模型对象的集合。

哪个模型带有ManyToManyField都没关系,但你只能在其中一个模型中使用它,而不能在两个模型中都使用它。

一般来说,ManyToManyField实例应该放在Django管理界面中被编辑的对象中。在上面的例子中,toppings在Pizza中(而不是Topping有pizzas ManyToManyField),因为一个比萨有多个掐尖儿比一个掐尖儿在多个比萨上更容易考虑。这就是上面我们使用的方式,Pizza管理表单将让用户选择掐尖儿。

参阅“多对多关系模型的例子(URL)”来看一下完整的例子。

ManyToManyField字段也接受一些额外的参数,这些参数在“模型字段参考(URL)”中解释。这些选项帮助你定义关系的工作方式,不过它们都是可选的。

1.3.5.3. 多对多关系的额外字段(Django 1.0新增)

当你只需要处理简单的多对多关系,就像混合和匹配比萨和掐尖儿,一个标准的ManyToManyField字段就是你全部的所需。然而,有些时候你需要让数据在两个模型之间产生联系。

例如,考虑一下跟踪乐队和乐队拥有的音乐家的应用程序的例子。这是一个人和这个人所在团队之间的多对多关系,因此你可以使用ManyToManyField来描述这个关系。然而,这种成员关系有很多你想要搜集的细节,比如这个人加入团队的时间。

对于这种情况,Django让你可以指定用来管理多对多关系的模型。然后你可以在中间模型中放入额外的字段。中间模型使用through参数指向像中间人一样工作的模型,来和ManyToManyField发生关系。对于四个音乐家的例子,代码可能像这样子:

class Person(models.Model):
    name = models.CharField(max_length=128)
    def __unicode__(self):
        return self.name
class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')
    def __unicode__(self):
        return self.name
class Membership(models.Model):
    person = models.ForeignKey(Person)
    group = models.ForeignKey(Group)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

当你建立中间模型时,你需要为模型明确地指定外键,以建立多对多关系。这个明确的声明定义了两个模型是如何产生联系的。

对于中间模型,有一些限制:

中间模型必须包含并且只包含一个到目标模型的外键(在上面的例子中是Person)。如果存在一个以上的到目标模型的外键,会产生校验错误。
中间模型必须包含并且只包含一个到源模型的外键(在上面的例子中是Group)。如果存在一个以上的到源模型的外键,会产生校验错误。
唯一的例外是,对于通过一个中间模型,带有到自己的多对多关系的模型。在这种情况下,两个到同一个模型的外键是允许的,但这两个外键会被看作是多对多关系的两个不同侧面。
当使用中间模型来定义一个到自己的多对多关系的模型是,你必须使用symmetrical=False(参阅“模型字段参考(URL)”)。

现在你已经建立了ManyToManyField来使用中间模型(在这个例子中是MemberShip),你可以开始创建一些多对多的对应关系了。具体来说是创建中间模型的一些实例:

>>> ringo = Person.objects.create(name='Ringo Starr')
>>> paul = Person.objects.create(name='Paul McCartney')
>>> beatls = 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()
[<Person: Ringo Starr>]
>>> ringo.group_set.all()
[<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()
[<Person:Ringo Starr>, <Person: Paul McCartney>]

和一般的多对对字段不同,你无法使用add、create或赋值(例如,beatles.members = [...])来创建关系:

#THIS WILL NOT WORK
>>> beatles.members.add(john)
#NEITHER WILL THIS
>>> beatles.members.create(name='George Harrison')
#ADD NEITHER WILL THIS
>>> beatles.members = [john, paul, ringo, george]

为什么呢?你不能只在Person和Group创建关系,你必须指定Membership模型需要的全部关系细节。简单的add、create和赋值调用没有提供方法来指定这些额外的信息。结果就是,对于使用中间模型的多对多关系它们被禁用了。创建这种类型的关系的唯一方法是创建中间模型的实例。

#Beatles have broken up
>>> beatles.members.clear()

一旦你通过创建中间模型的实例建立了多对多关系,你就可以进行查询了。就像普通的多对多关系那样,你可以使用多对多关系模型的属性来进行查询:

#Find all the groups with a member whose name starts with 'Paul'
>>> Group.objects.filter(memebers__name__startwith='Paul')
[<Group: The Beatles>]

因为你正在使用中间模型,你也可以使用它的属性来进行查询:
#Find all the members of the Beatles that joined after Jan 1 1961
>>> Person.objects.filter(
...    group__name='The Beatles',
...    membership__date__joined__gt=date(1961, 1, 1))
[<Person: Ringo Starr]

1.3.5.4. 一对一关系

要定义一对一关系,请使用OneToOneField。它的使用方法和其它字段一样:把它包含在模型的类属性中。

当对象以某种方式扩展了另一个对象的主键时,这对于对象的主键是最重要的。

OneToOneField要求一个位置参数:该模型相关的类。

例如,如果你将创建一个数据表places,你可能会在数据表中建立一些相当标准的东西,就像地址、电话号码等等。然后,如果你想在places上建立一个饭馆,你可以不必重复劳动,在Restaurant模型中复制这些字段,你可以建立一个带有到Place的OneToOneField(因为饭馆就是一个place;实际上,对于这种情况典型的做法是使用继承,这实际上是一种隐式的一对一关系)。

和外键一样,你可以定义循环关系和到未定义模型的关系;详情请参阅“模型字段参考(URL)”。

请参阅“一对一关系模型的例子(URL)”来看一下完整的例子。

OneToOneField也接受一个可选的参数,这个参数在“模型字段参考(URL)”有介绍。

OneToOneField类曾经会自动成为模型的主键。现在情况不再如此了(尽管如果你愿意你可以手动传递一个primary_key参数)。因此,现在一个模型可以拥有多个OneToOneField类型的字段。

1.3.6. 跨文件模型

在当前模型中建立和另一个应用程序中的模型的关系是非常完美没有问题的。要建立这样的关系,在当前模型所在文件的头部导入相关模型,然后在需要的时候引用相关模型即可。例如:

from mysite.geography.models import ZipCode
class Restaurant(models.Model):
    #...
    zip_code = models.ForeignKey(ZipCode)

1.3.7. 字段名限制

Django对字段名只有两个限制:

1) 字段名不能是Python的保留关键字,不然会导致Python语法错误。例如:

class Example(models.Model):
    pass = models.IntegerField()    #"pass" is a reserved word!

2) 字段名在一行中包含一个以上的下划线,这和Django的搜索查询语法的工作方式有关。例如:

class Example(models.Model):
    foo_bar = models.IntegerField()    #"foo__bar"有两个下划线!

这些限制是可以绕过的,因为你的字段名并不需要和数据表的列名匹配。请参考db_colum选项。

SQL保留字,比如join、where或select,可以用作模型字段名,因为Django在进行底层的SQL查询前会对所有数据表名和列名进行转义。具体来说是使用你所使用的数据库的引用语法。


本文引自:http://bbs.quickbest.com.cn/thread-63321-1-1.html
这里有更全的资料。

你可能感兴趣的:(sql,django,python,制造,音乐)