【问题标题】:Django Model Many-to-Many and Bridge TablesDjango 模型多对多和桥接表
【发布时间】:2019-01-30 22:47:18
【问题描述】:

我试图了解如何正确设置我的模型以建立多对多关系,我注意到在创建模型时有一个 ManyToManyField 选项,但我似乎无法理解它的逻辑以及如何使其正常工作。我想分享我的代码并一路解释。

from django.db import models

class Major(models.Model):
    name = models.CharField(max_length=30, db_index=True)

class School(models.Model):
    name = models.Charfield(max_length=50, db_index=True)
    majors = models.ManyToManyField(Major)

class Professor(models.Model):
    ProfessorIDS = models.IntegerField()
    ProfessorName = models.CharField(max_length=100)
    ProfessorRating = models.DecimalField(decimal_places=2,max_digits=4)
    NumberOfRatings = models.CharField(max_length=50)
    school = models.ForeignKey(School , on_delete=models.CASCADE)
    major = models.ForeignKey(Major , on_delete=models.CASCADE)

请注意,School TABLE (Class) 有一个多对多的专业,这本质上是我想要的,目标是让数据库允许在单个学校下存储多个专业。

在做了一些研究后,我得出的结论是,这没有意义,最好创建一个 Bridge Table 所以我决定像这样创建我的模型......

from django.db import models

class Major(models.Model):
    name = models.CharField(max_length=30, db_index=True)

class School(models.Model):
    name = models.Charfield(max_length=50, db_index=True)


class School_Majors(models.Model):
    school = models.ForeignKey(School, on_delete=models.CASCADE)
    major = models.ForeignKey(Major, on_delete=models.CASCADE)

class Professor(models.Model):
    ProfessorIDS = models.IntegerField()
    ProfessorName = models.CharField(max_length=100)
    ProfessorRating = models.DecimalField(decimal_places=2,max_digits=4)
    NumberOfRatings = models.CharField(max_length=50)
    school = models.ForeignKey(School , on_delete=models.CASCADE)
    major = models.ForeignKey(Major , on_delete=models.CASCADE)

这难道不是一种更合适的方式来设置数据库以便在学校中添加和删除多个专业,反之亦然?

【问题讨论】:

  • 你的两个sn-ps基本上没有区别。您认为明确定义 School_Majors 模型有什么优势? (也作为代码风格点,对类使用UpperCamelCase,对模型使用单数名称)。

标签: django python-3.x django-models


【解决方案1】:

最好建个桥接表

ManyToManyField 就是这样做的。你的两个 sn-ps 在功能上是相同的。

如果您可能希望在直通表上添加一些额外数据(在 Django 世界中称为),例如首次提供专业时的字段记录,您可以在 @ 上使用 through 参数987654326@,像这样:

from django.db import models

class Major(models.Model):
    name = models.CharField(max_length=30, db_index=True)


class School(models.Model):
    name = models.CharField(max_length=30, db_index=True)
    majors = models.ManyToManyField(Major, through='SchoolMajor')


class SchoolMajor(models.Model):
    major = models.ForeignKey(Major, on_delete=models.CASCADE)
    school = models.ForeignKey(School, on_delete=models.CASCADE)
    first_offered = models.DateField()

改编自here

【讨论】:

  • 我以为不会创建桥接数据库,谢谢您清除它。您对如何填充桥接表有任何建议吗?我将拥有 xlsx/csv 文件,其中包含将填充这些数据库的数据,但我无法弄清楚格式以及用于填充该数据的工具,而不是手动输入每个数据。
  • for./manage.py shell 提供的shell 中的循环将非常适合本地开发和测试。如果这是您需要经常做的事情,请考虑将其转换为management command。至于实际创建数据本身,创建所有Majors,创建所有Schools,然后针对每个学校或专业,根据您的选择执行school.majors.add(major)major.schools.add(school)
  • 您还可以使用./manage.py dumpdata 将最初创建的数据转换为fixture,以后可以使用./manage.py loaddata 将其还原到不同的数据库。
  • 如果我在 xlsx 文件中有这些数据,我从网站上抓取了一些数据并获得了大量数据,如数千行,我基本上想将这些数据定位在这样一个为了让它只填充该数据库,这个装置很有趣,但我觉得我需要很长时间才能格式化该数据。我使用了一个人口脚本,它对 xlsx 文件格式的魅力,对于 sqlite3,但由于这将由 3 个不同的表(一个是多对多)组成,我想看看是否还有其他的那里有快捷方式。
  • 就像我说的——在shell中一个for循环,用于本地开发和测试,如果需要多次执行,则发出管理命令。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-17
  • 2019-09-15
  • 2023-04-06
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 2011-12-20
相关资源
最近更新 更多