我现在正在定义我的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中表达这一点?


当前回答

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

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(...)

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

其他回答

您可以在多对多关系(即多对一关系)的多个方面使用外键,也可以在具有唯一约束的任何方面使用多对多(在任何方面)。

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

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

虽然《滚石》杂志的回答很好,直截了当,而且很实用,但我认为有两件事它没有解决。

如果OP想要强制一个电话号码不能同时属于Dude和Business 由于在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。

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

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(...)

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

首先我们来参观一下:

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中多对一由ForeignKey表示。

02)多对一关系:

SOLVE:

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

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

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

Nb:简单想想!!