如何在Django数据库中设置一对多的关系,使外键成为主键?

30 浏览
0 Comments

如何在Django数据库中设置一对多的关系,使外键成为主键?

我正在定义我的Django模型,我意识到模型字段类型中没有一个"OneToManyField"。我确定有一种方法可以做到这一点,所以我不确定自己漏掉了什么。我基本上有这样的情况:

class Dude(models.Model):
    # 一个人可以有0个或多个电话号码
    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 phoneNumbers;

我如何在Django中表达这个关系?

0
0 Comments

在Django中,没有提供直接的一对多关系(OneToMany),只能通过外键(ForeignKey)来描述多对一(ManyToOne)关系。虽然可以使用外键来描述一对多关系,但这种方式表达不够直观。

但是,我们可以使用多对多字段(ManyToManyField)来实现一对多关系。下面介绍如何使用ManyToMany字段:

1. 首先,在Django模型中定义两个相关的模型。例如,我们有一个"Category"模型和一个"Product"模型,一个分类可以对应多个产品。

from django.db import models
class Category(models.Model):
    name = models.CharField(max_length=100)
class Product(models.Model):
    name = models.CharField(max_length=100)
    categories = models.ManyToManyField(Category)

2. 在Product模型中,使用ManyToMany字段来表示与Category模型的关系。这将创建一个中间表,用于存储Product和Category之间的关联信息。

3. 现在,我们可以在代码中使用这种关系。例如,我们可以创建一个新的分类,并将其与某个产品关联起来。

category = Category.objects.create(name="Electronics")
product = Product.objects.create(name="Smartphone")
product.categories.add(category)

4. 我们还可以获取与某个产品相关联的所有分类。

product = Product.objects.get(name="Smartphone")
categories = product.categories.all()

通过使用ManyToMany字段,我们可以轻松地设置一对多关系,而无需使用外键作为主键。这种方法更加直观和灵活,可以更好地描述数据模型中的关系。如果你对这个主题感兴趣,可以阅读上面提到的文章,了解更多关于一对多关系在Django中的实现方式。

0
0 Comments

如何在Django数据库中设置一对多关系,使外键成为主键?

在Django中,一对多关系称为ForeignKey。然而,它只能在一个方向上工作,所以与其在Dude类中有一个number属性,你需要:

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.all()来访问Dude对象d的PhoneNumbers,然后对Business对象也是类似的。

我曾经以为ForeignKey意味着“一对一”。使用上面的例子,我应该有一个有多个PhoneNumbers的Dude,对吗?

我编辑了我的答案以反映这一点。是的,如果你指定ForeignKey(Dude, unique=True),ForeignKey才是一对一的,所以使用上面的代码,你将得到一个有多个PhoneNumbers的Dude。

stone-谢谢,我在评论中意识到自己的错误后才添加了那个。Unique=True并不像OneToOneField一样工作,我本来是想解释ForeignKey只使用一对一关系,如果你指定Unique=True。

你是对的,那是一种令人困惑的澄清方式。我本来是想修改而不是重写原始问题中的模型,但显示更有用的答案更有意义。已修复。

从PhoneNumber开始做这个+1。现在开始有点明白了。ForeignKey本质上是多对一的,所以你需要反过来实现一对多的关系 🙂

stone,如果你有50美元的话,当然可以 😉

有人能解释一下字段phonenumber_set的名称的重要性吗?我没有在任何地方看到它的定义。它是模型的名称,全部小写,后面加上"_set"吗?

这是外键的related_name。在向后相关的对象中有一些关于这些默认值的文档,可以在向后相关的对象中找到相关信息。

它能保护我们免受Dude和Business共享相同电话号码的影响吗?

请注意,类内的属性名必须与外部类和表名及其关键字相同。所以在我的例子中,我尝试了类似于mydude = models.ForeignKey(Dude)的东西,django/python没有抱怨任何问题,但是它不会返回对象,因为它尝试使用"primary key"而不是"dude_id"来选择数据库。显然,框架无法智能地从Dude类中获取数据库的主键名称。

没有一对多关系。这就是为什么你使用了多对多关系。

0
0 Comments

问题的出现原因:

在Django中处理一对多关系需要使用ForeignKey。在给出的例子中,每个Dude可以拥有一个PhoneNumber,而每个PhoneNumber可以属于多个Dude(Business同理)。

解决方法:

如果想要反向关联,需要在PhoneNumber模型中添加两个ForeignKey字段,一个指向Dude,一个指向Business。这样每个PhoneNumber可以属于一个Dude或者一个Business,并且Dude和Business可以拥有多个PhoneNumber。具体的代码如下:

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

可能需要将两个ForeignKey字段都设置为非必填(blank=True, null=True),或者添加一些自定义验证以确保至少有一个字段有值。比如,一个Business是否有一个通用号码,或者一个失业的Dude。

另一个需要提及的是ForeignKey中的related_name参数。在PhoneNumber类中,可以使用`dude = models.ForeignKey(Dude, related_name='numbers')`,然后可以使用`some_dude_object.numbers.all()`来获取所有相关的PhoneNumber(如果没有指定related_name,则默认为number_set)。

如果想让一个号码只属于Business或Dude中的一个,而不是同时属于两者,可以通过使用ContentTypes Framework来实现。不过,使用content types可能会变得非常复杂,如果只需要简单的关联关系,上述的简单方法可能更合适。

还有一个额外的问题是在模板中使用`object.comments.all()`时可能会出现错误,这时需要在视图中处理好相关的逻辑,然后将结果传递给模板进行展示。

以上是关于在Django数据库中设置一对多关系的问题的原因和解决方法的整理。

0