Django 如何与多对多字段建立外键关系?

Django 如何与多对多字段建立外键关系?,django,django-models,django-templates,django-views,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.

我有以下型号:

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)

对于这件作品的每位演员?

我想你要找的是通过表
。阅读更多关于它的信息

你的代码看起来像这样

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)

我想您要找的是通过表
。阅读更多关于它的信息

你的代码看起来像这样

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)
建模有点“古怪”。通常,人们希望您在
WorkMusic
模型上定义
ManyToManyField
,并使用
WorkCast
作为中间的“直通”模型。您可以使用指定。比如:

class WorkMusic(MPTTModel,Work):
name=models.CharField(最大长度=10,null=True,blank=True)
cast=models.ManyToManyField('cast',至='WorkCast')
类别转换(models.Model):
name=models.CharField(最大长度=100,null=True,blank=True)
定义(自我):
返回self.name
类工作类型转换(models.Model):
work=models.ForeignKey(
工作音乐,
详细名称=(工作),
相关_name='workcast',
空=真,
空白=真,
on_delete=models.PROTECT
)
cast=models.ForeignKey(
铸造
详细名称=u('cast'),
相关_name='workcast',
空白=真,
on_delete=models.PROTECT
)
最低注释=models.CharField(最大长度=10,空值=True,空值=True)
最高注释=models.CharField(最大长度=10,空值=True,空值=True)
因此,这里我们将为每个
WorkCast
对象编码,该对象与一个
WorkMusic
对象相关,另一个
Cast
对象与额外字段相关。但是,
WorkMusic
对象可以有零个、一个或多个相关的
WorkCast
对象,因此与零个、一个或多个
Cast
对象相关

注意:通常Django模型,就像Python中的所有类在PerlCase中都有一个名称,而不是snake\u case,因此它应该是:
WorkMusic
而不是
Work\u Music

建模有点“古怪”。通常,人们希望您在
WorkMusic
模型上定义
ManyToManyField
,并使用
WorkCast
作为中间的“直通”模型。您可以使用指定。比如:

class WorkMusic(MPTTModel,Work):
name=models.CharField(最大长度=10,null=True,blank=True)
cast=models.ManyToManyField('cast',至='WorkCast')
类别转换(models.Model):
name=models.CharField(最大长度=100,null=True,blank=True)
定义(自我):
返回self.name
类工作类型转换(models.Model):
work=models.ForeignKey(
工作音乐,
详细名称=(工作),
相关_name='workcast',
空=真,
空白=真,
on_delete=models.PROTECT
)
cast=models.ForeignKey(
铸造
详细名称=u('cast'),
相关_name='workcast',
空白=真,
on_delete=models.PROTECT
)
最低注释=models.CharField(最大长度=10,空值=True,空值=True)
最高注释=models.CharField(最大长度=10,空值=True,空值=True)
因此,这里我们将为每个
WorkCast
对象编码,该对象与一个
WorkMusic
对象相关,另一个
Cast
对象与额外字段相关。但是,
WorkMusic
对象可以有零个、一个或多个相关的
WorkCast
对象,因此与零个、一个或多个
Cast
对象相关

注意:通常Django模型,就像Python中的所有类在PerlCase中都有一个名称,而不是snake\u case,因此它应该是:
WorkMusic
而不是
Work\u Music


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


文档:

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


Docs:

我稍微简化了我的模型以提出这个问题,但我遇到了一些错误,所以我对我原来的问题做了一些修改,希望您能提供帮助。我有一个歌剧模型,它附在工作音乐上。这是因为并非所有的作品都是歌剧,我只想将相对论元数据附加到歌剧作品中。这仍然是正确的模型吗?我得到了这个错误。art_perf.WorkCast:(fields.E336)该模型被“art_perf.Opera.cast”用作中间模型,但它没有“Opera”或“cast”的外键。您如何将其添加到admin.py以添加数据?@HC:您是否将这两个
外键添加到您的
cast
Opera
,如答案中所示?好的。我明白问题所在。我制作了歌剧模型的附件。目前,运行时的速度明显减慢。另外,是否有一种方法可以构造admin.py,这样在Workcast中,我可以同时选择多个演员,并同时指定最高和最低音符范围?我稍微简化了我的模型来提问,但我遇到了一些错误,因此我对我的原始问题进行了一些修改,希望您能提供帮助。我有一个歌剧模型,它附在工作音乐上。这是因为并非所有的作品都是歌剧,我只想将相对论元数据附加到歌剧作品中。这仍然是正确的模型吗?我得到了这个错误。art_perf.WorkCast:(fields.E336)该模型被“art_perf.Opera.cast”用作中间模型,但它没有“Opera”或“cast”的外键。您如何将其添加到admin.py以添加数据?@HC:您添加了这两个
外键吗