如何与多对多领域建立外键关系?

时间:2020-01-30 19:27:49

标签: django django-models django-templates django-views

我有以下型号:

class Work_Music(MPTTModel, Work):
    name = models.CharField(max_length=10, null=True, blank=True)

class Opera(models.Model):
    work = models.OneToOneField(Work_Music, verbose_name=_('work_music'), related_name='opera', on_delete=models.PROTECT)
    cast = models.ManyToManyField('Cast', through='WorkCast')
    source_writer = models.ForeignKey(Person, verbose_name=_('author'), null=True, blank=True, on_delete=models.PROTECT)
    numbering = models.CharField(max_length=8000, null=True, blank=True)
    work_type = models.CharField(max_length=8000, null=True, blank=True)

class Cast(models.Model):
    name = models.CharField(max_length=100, null=True, blank=True)

    def __str__(self):
        return self.name


class WorkCast(models.Model):
    work = models.ForeignKey(Work_Music, verbose_name=_('work'), related_name='workcast', null=True, blank=True, on_delete=models.PROTECT)
    cast = models.ManyToManyField(Cast, verbose_name=_('cast'), related_name='workcast', blank=True)

    def __str__(self):
        return "%s" % (
            ", ".join(character.name for character in self.cast.all())
        )

当前数据结构为:

WorkCast
   |-----> Opera
   |-----> Opera cast member #1
           Opera cast member #2
           Opera cast member #3

我现在想为每个铸件附加一个唱歌范围,以完成这项特定的工作。像这样的东西:

WorkCast
   |-----> (ForeignKey)   Opera
   |-----> (Many-to-many) Opera cast member #1, lowest note: c, highest note: A#
                          Opera cast member #2, lowest note: b, highest note: D
                          Opera cast member #3, lowest note: a, highest note: E

如何附加:

lowest_note = models.CharField(max_length=10, null=True, blank=True)
highest_note = models.CharField(max_length=10, null=True, blank=True)

该特定作品的每个演员?

3 个答案:

答案 0 :(得分:0)

我认为您正在寻找的是through table。进一步了解here

您的代码如下所示。

class WorkCast(models.Model):
    work = models.ForeignKey(Work_Music, verbose_name=_('work'), related_name='workcast', null=True, blank=True, on_delete=models.PROTECT)
    cast = models.ManyToManyField(Cast, verbose_name=_('cast'), related_name='workcast', blank=True, through='SingRange')

    def __str__(self):
        return "%s" % (
            ", ".join(character.name for character in self.cast.all())
        )

class SingRange(models.Model):
    lowest_note = models.CharField(max_length=10, null=True, blank=True)
    highest_note = models.CharField(max_length=10, null=True, blank=True)

答案 1 :(得分:0)

建模有点“ 奇数”。通常,人们希望您在ManyToManyField模型上定义WorkMusic,并将WorkCast用作两者之间的“直通”模型。您可以使用through=… parameter [Django-doc]进行指定。喜欢:

class WorkMusic(MPTTModel, Work):
    name = models.CharField(max_length=10, null=True, blank=True)
    cast = models.ManyToManyField('Cast', through='WorkCast')


class Cast(models.Model):
    name = models.CharField(max_length=100, null=True, blank=True)

    def __str__(self):
        return self.name


class WorkCast(models.Model):
    work = models.ForeignKey(
        WorkMusic,
        verbose_name=_('work'),
        related_name='workcast',
        null=True,
        blank=True,
        on_delete=models.PROTECT
    )
    cast = models.ForeignKey(
        Cast,
        verbose_name=_('cast'),
        related_name='workcast',
        blank=True,
        on_delete=models.PROTECT
    )
    lowest_note = models.CharField(max_length=10, null=True, blank=True)
    highest_note = models.CharField(max_length=10, null=True, blank=True)

在这里,我们将为每个与{em> one WorkCast对象和 one WorkMusic相关的Cast对象进行编码反对多余的字段。 WorkMusic对象可以具有个零,一个或多个相关的WorkCast对象,因此与零个,一个或多个 { {1}}个对象。

注意:通常是Django模型,就像Python中的所有类在 PerlCase 中都有一个名称,而不是 snake_case 一样,因此它应该是:Cast而不是 WorkMusic

答案 2 :(得分:0)

您可以为m2m关系创建自己的模型,并将所有必需的字段添加到该模型。您可以在ManyToManyField中通过参数指定使用此模型。

文档:https://docs.djangoproject.com/en/3.0/topics/db/models/#extra-fields-on-many-to-many-relationships