在Django模型中何时使用一对一关系?

13 投票
3 回答
11140 浏览
提问于 2025-04-18 16:34

我看到一些地方提到,在Django模型中,一对一的关系通常应该只用于继承,或者用来访问一些平时无法直接访问的模型,比如Django的用户模型。

不过,有时候你会遇到一种情况,就是一个对象总是会有一个对应的对象,而你可能会想把这两个对象分开来处理。举个例子,假设你的应用是用来存储汽车的信息。每辆车都有一个司机,而每个司机只开一辆车。这样看来,把车和司机分成两个不同的模型是不是更合理呢?

3 个回答

0

OneToOneField() 是用来扩展 用户模型 的,这样可以添加一些额外的字段,下面会有示例。*你可以查看 我的回答,里面解释了如何使用 OneToOneField() 来添加额外的字段:

# "account/models.py"

from django.db import models
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.OneToOneField(
        User, 
        verbose_name=_("user"), 
        on_delete=models.CASCADE
    )
    age = models.PositiveSmallIntegerField(_("age"))
    gender = models.CharField(_("gender"), max_length=20)
    married = models.BooleanField(_("married"))
4

Django的文档给出了一个很好的解释:

比如说,如果你在建立一个“地点”的数据库,你会在数据库里建立一些常规的信息,比如地址、电话号码等等。然后,如果你想在这些地点的基础上建立一个餐厅的数据库,干嘛要重复之前的字段呢?你可以让餐厅模型和地点模型之间建立一个一对一的关系(因为餐厅“就是”一个地点;实际上,处理这个关系时,通常会用到继承的概念。每辆车都有一个司机,而每个司机只开一辆车。把车和司机分开管理,这样的设计就不太合理了)。

Django使用一对一关系来建模继承(可能在内部也会用到这个关系,不过我还没去查看源代码)。我觉得如果Django提供了一个工具,而你能用这个工具来合理地解决问题,那为什么不使用呢?这看起来很有道理:如果一辆车只有一个司机,那就用Django提供的工具(OneToOneField)在数据库中强制执行这个规则。

19

想象一下,你有一家公司的内部工具,用来列出所有员工的信息,比如他们的职位、办公室、部门、薪水等等。你可能会在Django的models.py文件里创建一个叫做Employee的类,可能长得像这样:

class Employee(models.Model):
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)
    position = models.CharField(max_length=255)
    office = models.CharField(max_length=20)
    salary = models.IntegerField()
    department = models.ForeignKey(Department, related_name='employees')

但是出于某些原因,你不想让所有员工都能看到薪水。也许在管理区域有很多人有编辑权限,他们可能会决定把薪水信息单独放到一个模型里,然后修改Employee模型:

class Employee(models.Model):
    # above attributes
    salary = models.OneToOneField(Salary)

当然,还有其他方法可以隐藏这些信息,但一种可能的做法是把信息分成两个表,尽管它们之间的关系其实是1:1。

假设你的公司是一家软件公司,并且你引入了结对编程。每个员工都有一个编程搭档,可能只有一个搭档。所以你又要调整你的模型:

class Employee(models.Model):
    # above attributes
    pair_programmer = models.OneToOneField('self')

这就形成了一个递归的1:1关系。

1:1关系并不常见,在初学者的教程中也很少见到,但如果有一些特定的需求,你可能会发现自己需要创建1:1关系来解决问题。

这里有一个我工作中的真实例子。我是一名生物信息学家,开发微生物的软件。微生物被分类为属和种。每个属可以包含一个或多个种,但一个种只能属于一个属。这是一个明显的1:n关系。但现在,每个属都有一个类型种,只有一个,并且这个类型种只能属于一个属。在这里,我使用了models.OneToOneField,除了models.ForeignKey

不要过于担心1:1关系。等你遇到具体问题时,你自然会明白是否需要使用1:1关系。

撰写回答