首先,是的:我已经阅读过Django的foreign key and many-to-many documentation,但我仍然没有100%明确如何在实际层面上实现关系,特别是关于关系的层次结构。
我知道如何形成一对一的关系。但是,在更概念的层面上,哪个模型应该包含对另一个模型的引用?我们假设我有Citizen
和Passport
。现在,很明显一个Citizen
只能有一个Passport
而反之,理想,如果Citizen
包含一个字段引用到Passport
,或Passport
模型是否包含对其所属的Citizen
的引用?
为了简单起见,我们假设我有一个Person
模型和一个Trip
模型(Trip
,就像出去旅行一样)。许多Persons
可以参与一个Trip
。或者换句话说:Person
可以参与许多Trips
,而在任何单Trip
中,很多Persons
都可以参与。这看起来像是多对多关系,但同样,理想,哪个模型应该包含关系的定义,Person
带有trips
字段或者带participants
字段的旅行?为什么?它是否会产生任何实际差异?
谢谢。
答案 0 :(得分:3)
这取决于您的业务逻辑。根据经验,我建议考虑管理员应用程序。您想如何添加新对象?
添加新对象时,您希望如何添加相关对象?
假设您有这些模型:
Citizen(models.Model):
name = models.CharField()
Passport(models.Model):
number = models.CharField()
citizen = models.OneToOneField('Citizen', related_name='passport')
添加新护照对象时,如果尚未存在新公民,则可以添加新公民。因为这对我来说看起来不合逻辑,所以我将关系更改为:
Citizen(models.Model):
# other fields
passport = models.OneToOneField('Passport', related_name='citizen')
现在我们可以在管理员中添加新的公民对象,并在同一页面中添加相关的护照对象。
如果您使用管理员应用程序,这将引导您进行更符合人体工程学的设计。
编辑:使用多对多示例展开
m2m关系的更好示例是StackOverflow - 有问题和标签。一个问题有很多标签,标签有很多问题。让我们说模型看起来像这样:
Question(models.Model):
title = models.CharField()
body = models.TextField()
author = models.CharField()
tags = models.ManyToManyField('Tag', related_name='questions')
Tag(models.Model):
name = models.CharField()
为什么我们将关系置于问题中?这应该是非常合理的 - 在创建新问题时,您需要为其设置标记。创建新标签时,您不关心与之相关的任何问题。您可以创建标记,稍后在创建问题时,将它们与标记相关联 如果标签不存在,您可以在添加新问题时从管理员添加标签。
我希望第二个例子更明显。
答案 1 :(得分:1)
你应该拥有的心理模型是父母和孩子。每个关系都有两个模型。因此,将其中一个视为父模型或主模型,并将另一个视为子模型或辅助模型。
注意:始终将您的关系字段放在CHILD模型中。
以下是我如何解决您的问题:
对于第一个,我将有一个心理模型,公民是父母,护照是孩子。
Route::get('clubs', function () {
return App\Clubs::select('name', 'city')->get();
});
对于第二个问题,也要这样做。我会选择Person作为父模型,Trip作为子模型。
class Citizen(models.Model):
name = models.CharField(max_length=255)
info = models.TextField()
class Passport(models.Model):
owner = models.OneToOneField(Citizen)
unique_no = models.CharField(max_length=30, unique=True)
如果您有class Person(models.Model):
name = models.CharField(max_length=255)
info = models.TextField()
class Trip(models.Model):
person = models.ManyToManyField(Person)
info = models.TextField()
,则可以使用它来打开数据库,并根据您的模型检查创建的表格。然后,您将更清楚地了解Django如何看待您的模型。
答案 2 :(得分:1)
这背后的理论称为database normalization,如果您想了解更多关于如何构建数据的信息,那么您应该查看最佳实践的阶梯。
第三种形式告诉我们:
“[每个]非密钥[属性]必须提供关于密钥,整个密钥以及密钥的事实。”
因此,对于ForeignKey字段,它应该在Child模型上,因为它不告诉我们关于父项的任何内容,但它确实告诉我们孩子所属的父项。