django 数据表关系学习和应用
数据表有 一对一,一对多,多对多,关系
在django 中如何实现?
django 提供了三种最常见的数据库关联关系方法:多对一,多对多,一对一
多对一关联:
定义多对一关联关系,使用django.db.model.ForeignKey 类,就和其它 Field
字段类型一样,只需要在你模型中添加一个值为该类的属性。
ForeignKey 需要添加一个 位置参数,即你想要关联的模型类名
from django.db import models #被关联类
#唯一方,制造商是惟一的 class Manufacturer(models.Model): # ... pass #设有关联的字段类
#多方,car 有很多辆,与 制造方只有一个关系 class Car(models.Model):
#这里的定义方是,设置一个制造方的字段,manufacturer
#其中,标红的,是需要关联的类.
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE) # ...
多对多关系
定义一个多对多的关联关系,使用 django.db.models.ManyToManyField
类。就和其他 Field
字段类型一样,只需要在你模型中添加一个值为该类的属性。
ManyToManyField
类需要添加一个位置参数,即你想要关联的模型类名。
例如:如果 Pizza
含有多种 Topping
(配料) -- 也就是一种 Topping
可能存在于多个 Pizza
中,并且每个 Pizza
含有多种 Topping
--那么可以这样表示这种关系:
1 from django.db import models 2 3 4 class Topping(models.Model): 5 # ... 6 pass 7 8 9 class Pizza(models.Model): 10 # ... 11 toppings = models.ManyToManyField(Topping)
和 ForeignKey
类一样,你也可以创建 自关联关系 (一个对象与他本身有着多对多的关系)和 与未定义的模型的关系 。
建议设置 ManyToManyField
字段名(上例中的 toppings
)为一个复数名词,表示所要关联的模型对象的集合。
对于多对多关联关系的两个模型,可以在任何一个模型中添加 ManyToManyField
字段,但只能选择一个模型设置该字段,即不能同时在两模型中添加该字段。
一般来讲,应该把 ManyToManyField
实例放到需要在表单中被编辑的对象中。在之前的例子中, toppings
被放在 Pizza
当中(而不是 Topping
中有指向 pizzas
的 ManyToManyField
实例 )因为相较于配料被放在不同的披萨当中,披萨当中有很多种配料更加符合常理。按照先前说的,在编辑 Pizza
的表单时用户可以选择多种配料.
在多对多(many-to-many)关系中添加添加额外的属性字段¶
如果你只是想要一个类似于记录披萨和配料之间混合和搭配的多对多关系,标准的 ManyToManyField
就足够你用了。但是,有时你可能需要将数据与两个模型之间的关系相关联。
举例来讲,考虑一个需要跟踪音乐人属于哪个音乐组的应用程序。在人和他们所在的组之间有一个多对多关系,你可以使用 ManyToManyField
来代表这个关系。然而,你想要记录更多的信息在这样的关联关系当中,比如你想要记录某人是何时加入一个组的。
对于这些情况,Django 允许你指定用于控制多对多关系的模型。你可以在中间模型当中添加额外的字段。在实例化 ManyToManyField
的时候使用 through
参数指定多对多关系使用哪个中间模型。对于我们举的音乐家的例子,代码如下:
1 from django.db import models 2 3 4 class Person(models.Model): 5 name = models.CharField(max_length=128) 6 7 def __str__(self): 8 return self.name 9 10 11 class Group(models.Model): 12 name = models.CharField(max_length=128) 13 members = models.ManyToManyField(Person, through="Membership") 14 15 def __str__(self): 16 return self.name 17 18 # 这是自定义了一张 多对多的关系表.
#因为多对多关系中,django 在不指定关系表的情况下,会自动生成一个 中间关系表,
#且只有 两个表的 id字段,没有其他任何字段.
# 如果 你想记录 多对多关系中,更多信息,就需要 自定义 一个 关系表.
# 并拓展相应的字段,来实现
# 使用 through = "XXXX"表类,来指定 关联关系.
# 这个将在 自己的事例中使用到.
19 class Membership(models.Model): 20 person = models.ForeignKey(Person, on_delete=models.CASCADE) 21 group = models.ForeignKey(Group, on_delete=models.CASCADE) 22 date_joined = models.DateField() 23 invite_reason = models.CharField(max_length=64)
你需要在设置中间模型的时候,显式地为多对多关系中涉及的中间模型指定外键。这种显式声明定义了这两个模型之间是如何关联的。
在中间模型当中有一些限制条件:
- 你的中间模型要么有且 仅 有一个指向源模型(我们例子当中的
Group
)的外键,要么你必须通过ManyToManyField.through_fields
参数在多个外键当中手动选择一个外键,如果有多个外健且没有用through_fields
参数选择一个的话,会出现验证错误。对于指向目标模型(我们例子当中的Person
)的外键也有同样的限制。 - 在一个用于描述模型当中自己指向自己的多对多关系的中间模型当中,可以有两个指向同一个模型的外健,但这两个外健分表代表多对多关系(不同)的两端。如果外健的个数 超过 两个,你必须和上面一样指定
through_fields
参数,要不然会出现验证错误。
现在你已经设置好了你的 ManyToManyField
来使用你的中介模型(在这种情况下是 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>]>
一对一关联¶
使用 OneToOneField
来定义一对一关系。就像使用其他类型的 Field
一样:在模型属性中包含它。
当一个对象以某种方式“继承”另一个对象时,这对该对象的主键非常有用。
OneToOneField
需要一个位置参数:与模型相关的类。
例如,当你要建立一个有关“位置”信息的数据库时,你可能会包含通常的地址,电话等字段。接着,如果你想接着建立一个关于关于餐厅的数据库,除了将位置数据库当中的字段复制到 Restaurant
模型,你也可以将一个指向 Place
OneToOneField
放到 Restaurant
当中(因为餐厅“是一个”地点);事实上,在处理这样的情况时最好使用 模型继承 ,它隐含的包括了一个一对一关系。
1 from django.db import models 2 3 4 class Place(models.Model): 5 name = models.CharField(max_length=50) 6 address = models.CharField(max_length=80) 7 8 def __str__(self): 9 return f"{self.name} the place" 10 11 12 class Restaurant(models.Model): 13 place = models.OneToOneField( 14 Place, 15 on_delete=models.CASCADE, 16 primary_key=True, 17 ) 18 serves_hot_dogs = models.BooleanField(default=False) 19 serves_pizza = models.BooleanField(default=False) 20 21 def __str__(self): 22 return "%s the restaurant" % self.place.name 23 24 25 class Waiter(models.Model): 26 restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE) 27 name = models.CharField(max_length=50) 28 29 def __str__(self): 30 return "%s the waiter at %s" % (self.name, self.restaurant)
OneToOneField
字段还接受一个可选的 parent_link
参数。
OneToOneField
类通常自动的成为模型的主键,这条规则现在不再使用了(然而你可以手动指定 primary_key
参数)。因此,现在可以在单个模型当中指定多个 OneToOneField
字段。
数据表中,多字段联合唯一 ,如何实现?
联合唯一这个也要定义,还要重新迁移表
否则表的的定义方式有欠缺.
unique_together
¶
Options.
unique_together
¶-
一组字段名,合起来必须是唯一的:
unique_together = [["driver", "restaurant"]]
这是一个列表,这些列表在一起考虑时必须是唯一的。它 在Django 管理中使用,并在数据库级别执行(即在
CREATE TABLE
语句中包含适当的UNIQUE
语句)。为方便起见,
unique_together
在处理单组字段时可以是一个单一的列表:unique_together = ["driver", "restaurant"]
ManyToManyField
不能包含在unique_together
中。(甚至不清楚这意味着什么!)如果需要验证与ManyToManyField
相关的唯一性,请尝试使用信号或显式的through
模型。在模型验证过程中,当约束条件被违反时引发的
ValidationError
具有unique_together
错误代码
自关联字段字的一对多查询 ,如何实现?
关联实现:
ForeignKey
¶
- class
ForeignKey
(to, on_delete, **options)¶
一个多对一的关系。需要两个位置参数:模型相关的类和 on_delete
选项。
要创建一个递归关系——一个与自己有多对一关系的对象——使用 models.ForeignKey('self', on_delete=models.CASCADE)
。
关联查询:
在Django中,自关联的一对多查询指的是一个模型中的一个字段关联到了模型本身。例如,一个Comment模型可能有一个外键指向它自己,表示每个评论都可以回复另一个评论。
以下是一个简单的例子:
1 from django.db import models 2 3 class Comment(models.Model): 4 text = models.TextField() 5 reply_to = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='replies') 6 7 def __str__(self): 8 return self.text
查询所有顶级评论(即没有reply_to的评论):
top_level_comments = Comment.objects.filter(reply_to__isnull=True)
查询特定评论的所有回复:
在这个例子中,top_level_comments
是一个顶级评论的查询集,而 replies
是作为 comment
对象的回复的查询集。
#如果没有 指定related_name ,那就按照 默认的 形式:XXX_set来代表 查询集
例 :“反向” 关联¶
若模型有 ForeignKey
,外键关联的模型实例将能访问 Manager
,后者会返回第一个模型的所有实例。默认情况下,该 Manager
名为 FOO_set
, FOO
即源模型名的小写形式。 Manager
返回 QuerySets
,后者能以 “检索对象” 章节介绍的方式进行筛选和操作。
>>> b = Blog.objects.get(id=1) >>> b.entry_set.all() # Returns all Entry objects related to Blog. # b.entry_set is a Manager that returns QuerySets. >>> b.entry_set.filter(headline__contains="Lennon") >>> b.entry_set.count()
在 django 设置model ,然后迁移生成数据表,(database)方便还是直接使用mysql ,在数据库中创建表方便.
数据库中,即mysql 定义 外键,如何实现?
这个问题,稍微复杂点,单独来起说明