如何在Django中表达一对多的关系

Naf*_*Kay 150 django django-models

我正在定义我的Django模型,我意识到OneToManyField模型字段类型中没有.我确定有办法做到这一点,所以我不确定我错过了什么.我基本上有这样的事情:

class Dude(models.Model):
    numbers = models.OneToManyField('PhoneNumber')

class PhoneNumber(models.Model):
    number = models.CharField()
Run Code Online (Sandbox Code Playgroud)

在这种情况下,每个都Dude可以有多个PhoneNumbers,但关系应该是单向的,因为我不需要知道PhoneNumberDude拥有它本身,因为我可能有很多不同的对象拥有PhoneNumber实例,例如Businessfor例:

class Business(models.Model):
    numbers = models.OneToManyField('PhoneNumber')
Run Code Online (Sandbox Code Playgroud)

我会OneToManyField在模型中用什么替换(哪些不存在)来表示这种关系?我来自Hibernate/JPA,宣布一对多的关系就像:

@OneToMany
private List<PhoneNumber> phoneNumbers;
Run Code Online (Sandbox Code Playgroud)

我怎么能在Django中表达这个?

rol*_*one 118

要在Django中处理一对多关系,您需要使用ForeignKey.

关于ForeignKey的文档非常全面,应该回答您的所有问题:

https://docs.djangoproject.com/en/dev/ref/models/fields/#foreignkey

您的示例中的当前结构允许每个Dude有一个数字,每个数字属于多个Dudes(与Business相同).

如果你想要反向关系,你需要在PhoneNumber模型中添加两​​个ForeignKey字段,一个到Dude,一个到Business.这将允许每个号码属于一个Dude或一个Business,并且Dudes和Business可以拥有多个Numbers.我想这可能就是你所追求的.

class Business(models.Model):
    ...
class Dude(models.Model):
    ...
class PhoneNumber(models.Model):
    dude = models.ForeignKey(Dude)
    business = models.ForeignKey(Business)
Run Code Online (Sandbox Code Playgroud)

  • 一个相关的事情是ForeignKey的"related_name"参数.所以在PhoneNumber类中你有'dude = models.ForeignKey(Dude,related_name ='numbers')`然后你可以使用`some_dude_object.numbers.all()`获取所有相关的数字(如果你不喜欢的话)不要指定"related_name",它默认为"number_set"). (50认同)
  • 鉴于上述问题,你能给我一个例子吗?我可能只是完全错过了它,但我现在已经阅读了Django文档一段时间了,目前还不清楚如何建立这种关系. (3认同)
  • 可能想要使两个不需要的ForeignKeys(空白= True,null = True),或添加某种自定义验证以确保至少有一个或另一个.具有通用号码的企业的情况如何?还是一个失业的家伙? (3认同)

sti*_*ing 36

在Django中,一对多关系称为ForeignKey.但是,它只能在一个方向上工作,所以不需要具有numberDude所需的属性

class Dude(models.Model):
    ...

class PhoneNumber(models.Model):
    dude = models.ForeignKey(Dude)
Run Code Online (Sandbox Code Playgroud)

许多型号可以有ForeignKey一个其他的模式,所以这将是有效的具有第二属性PhoneNumber,使得

class Business(models.Model):
    ...
class Dude(models.Model):
    ...
class PhoneNumber(models.Model):
    dude = models.ForeignKey(Dude)
    business = models.ForeignKey(Business)
Run Code Online (Sandbox Code Playgroud)

您可以访问PhoneNumber■对于Dude对象dd.phonenumber_set.objects.all(),然后做一个类似的Business对象.

  • 从"PhoneNumber"中执行此操作的+1.现在它开始变得有意义了.`ForeignKey`基本上是多对一的,所以你需要向后做以获得一对多:) (7认同)
  • 我编辑了我的答案以反映这一点.是.如果指定`ForeignKey(Dude,unique = True)`,那么`ForeignKey`只是一对一的,所以使用上面的代码,你会得到一个带有多个`PhoneNumber`的`Dude`. (5认同)
  • 我假设`ForeignKey` 意味着“一对一”。使用上面的示例,我应该有一个包含许多“电话号码”的“Dude”,对吗? (2认同)
  • 有人可以解释字段`phonenumber_set`名称的意义吗?我没有看到它在任何地方定义.它是模型的名称,在所有小写字母中,附加"_set"? (2认同)

She*_*hid 17

django足够聪明。实际上我们不需要定义oneToMany字段。它将由django您自动生成:-)。我们只需要foreignKey在相关表中定义即可。换句话说,我们只需要使用 来定义ManyToOne关系foreignKey

class Car(models.Model):
    // wheels = models.oneToMany() to get wheels of this car [**it is not required to define**].


class Wheel(models.Model):
    car = models.ForeignKey(Car, on_delete=models.CASCADE)  
Run Code Online (Sandbox Code Playgroud)

如果我们想获得特定汽车的车轮列表。我们将使用python's自动生成的对象wheel_set。对于汽车,c您将使用c.wheel_set.all()


val*_*ame 16

更清楚的是 - Django中没有OneToMany,只有ManyToOne - 这是上面描述的Foreignkey.您可以使用Foreignkey描述OneToMany关系,但这是非常不可思议的.

一篇关于它的好文章:https: //amir.rachum.com/blog/2013/06/15/a-case-for-a-onetomany-relationship-in-django/


小智 15

您可以在OneToMany关系的多个方面使用外键(即ManyToOne关系)或使用ManyToMany(在任何一方)具有唯一约束的外键.


rab*_*eye 13

虽然滚石的回答很好,直接且实用,但我认为有两件事没有解决。

  1. 如果 OP 想要强制执行电话号码不能同时属于 Dude 和企业
  2. 由于在 PhoneNumber 模型上而不是在 Dude/Business 模型上定义关系而产生的不可避免的悲伤感。当额外的地球人来到地球时,我们想要添加一个 Alien 模型,我们需要修改 PhoneNumber(假设 ET 有电话号码),而不是简单地向 Alien 模型添加“phone_numbers”字段。

介绍内容类型框架,它公开了一些对象,允许我们在 PhoneNumber 模型上创建“通用外键”。然后,我们可以定义 Dude 和 Business 上的反向关系

from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.db import models

class PhoneNumber(models.Model):
    number = models.CharField()

    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    owner = GenericForeignKey()

class Dude(models.Model):
    numbers = GenericRelation(PhoneNumber)

class Business(models.Model):
    numbers = GenericRelation(PhoneNumber)
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅文档,也可以查看本文以获取快速教程。

此外,这里是一个文章是论证使用通用FKS的。