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

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

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


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

在这种情况下,每个Dude可以有多个PhoneNumber,但这种关系应该是单向的,因为我不需要从PhoneNumber中知道哪个Dude拥有它,因为我可能有许多不同的对象拥有PhoneNumber实例,例如Business:

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

我将在模型中替换OneToManyField(它不存在)来表示这种关系?我来自Hibernate/JPA,在那里声明一对多关系非常简单:

@OneToMany
private List<PhoneNumber> phoneNumbers;

如何在Django中表达这一点?

328570 次浏览

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

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

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

示例中的当前结构允许每个Dude拥有一个数字,并且每个数字属于多个Dude(与Business相同)。

如果你想要相反的关系,你需要给PhoneNumber模型添加两个ForeignKey字段,一个给Dude,一个给Business。这将允许每个号码属于一个人或一个企业,并使人和企业能够拥有多个号码。我觉得这可能就是你要找的东西。

class Business(models.Model):
    ...
class Dude(models.Model):
    ...
class PhoneNumber(models.Model):
    dude = models.ForeignKey(Dude)
    business = models.ForeignKey(Business)

在Django中,一对多关系被称为ForeignKey。然而,它只在一个方向上工作,所以你需要的不是类Dudenumber属性

class Dude(models.Model):
...


class PhoneNumber(models.Model):
dude = models.ForeignKey(Dude)

许多模型可以有一个ForeignKey到另一个模型,所以有第二个属性PhoneNumber是有效的,这样

class Business(models.Model):
...
class Dude(models.Model):
...
class PhoneNumber(models.Model):
dude = models.ForeignKey(Dude)
business = models.ForeignKey(Business)

你可以通过d.phonenumber_set.objects.all()访问Dude对象d的__abc0,然后对Business对象做类似的操作。

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

更清楚地说,Django中没有OneToMany,只有ManyToOne,也就是上面描述的Foreignkey。你可以使用Foreignkey来描述OneToMany关系,但这是非常缺乏表现力的。

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

如果“许多”模型本身不能证明创建模型的合理性(这里不是这样,但它可能对其他人有益),另一种替代方法是依赖于特定的PostgreSQL数据类型,通过Django Contrib包

Postgres可以处理数组JSON数据类型,当many-ies只能绑定到一个的单个实体时,这可能是处理一对多的一个很好的变通方法。

Postgres允许您访问数组的单个元素,这意味着查询可以非常快,并避免应用程序级的开销。当然,还有Django实现了一个很酷的API来利用这个特性。

它显然有不能移植到其他数据库后端的缺点,但我认为它仍然值得一提。

希望它可以帮助一些人寻找想法。

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

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)

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

虽然《滚石》杂志的答案是好的,直接的和功能性的,我认为有两件事它不能解决。

  1. 如果OP想要强制一个电话号码不能同时属于Dude和Business
  2. 由于在PhoneNumber模型上定义关系而不是在Dude/Business模型上定义关系而产生的不可避免的悲伤感觉。当外星人来到地球时,我们想要添加一个Alien模型,我们需要修改PhoneNumber(假设外星人有电话号码),而不是简单地向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)

有关详细信息,请参阅文档,也可以查看这篇文章以获得快速教程。

此外,这里是一篇文章,它向反对争论泛型fk的使用。

首先我们来参观一下:

01)一对多关系:

ASSUME:


class Business(models.Model):
name = models.CharField(max_length=200)
.........
.........
phone_number = models.OneToMany(PhoneNumber) (NB: Django do not support OneToMany relationship)


class Dude(models.Model):
name = models.CharField(max_length=200)
.........
.........
phone_number = models.OneToMany(PhoneNumber) (NB: Django do not support OneToMany relationship)


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

注意:Django没有提供任何OneToMany关系。所以在Django中不能使用upper方法。但是我们需要在关系模型中进行转换。那么我们能做什么呢?在这种情况下,我们需要将关系模型转换为反向关系模型。

在这里:

关系模型=一个多

所以,反向关系模型=多对一

注意:Django支持多对一关系在Django中ManyToOne由ForeignKey表示。

02)多对一关系:

SOLVE:


class Business(models.Model):
.........
.........


class Dude(models.Model):
.........
.........


class PhoneNumber(models.Model):
........
........
business = models.ForeignKey(Business)
dude = models.ForeignKey(Dude)

Nb:简单想想!!

实际上,一对多关系是非常有用的。我是这样做的:

class Dude(models.Model):
number = models.ManyToManyField(PhoneNumber)


def save(self, *args, **kwargs):
if Dude.objects.get(number=self.number):
raise Exception("Dude, this number has been used.")
return super(Dude, self).save(*args, **kwargs)


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

这样可以保证号码只使用一次。

一对多关系意味着一个模型记录可以有许多其他与它相关联的模型记录。

from django.db import models


class Menu(models.Model):
name = models.CharField(max_length=30)


class Item(models.Model):
menu = models.ForeignKey(Menu)
name = models.CharField(max_length=30)
description = models.CharField(max_length=100)

尽管这里的大多数答案在定义关系时传递了允许您定义OneToManyRelationship的关系,但它们实际上是多对多关系的定义。

下面是一个更准确的实现:

class Dude(models.Model):
name = models.CharField(max_length=256, unique=True)


class PhoneNumber(models.Model):
number = models.CharField(max_length=256, unique=True)


class DudePhoneNumbers(models.Model):
dude = models.ForeignKey(Dude, related_name="phone_number_relations", on_delete=models.CASCADE)
phone_number = models.OneToOneField(PhoneNumber, related_name="dude_relation", on_delete=models.CASCADE)