我有以下型号:
class Ensemble(Group):
name = models.CharField(max_length=100, null=True, blank=True)
instrumentation = models.ForeignKey(Instrumentation -> Instrument, verbose_name=_('part'), related_name='ensemble_member', null=True, blank=True, on_delete=models.PROTECT)
class EnsembleMember(models.Model):
person = models.ForeignKey(Person, verbose_name=_('member'), on_delete=models.PROTECT)
instrument ???? = models.ForeignKey(Instrumentation, verbose_name=_('part'), related_name='ensemble_member', null=True, blank=True, on_delete=models.PROTECT) //This is the line in question
ensemble = models.ForeignKey(Ensemble, verbose_name=_('ensemble'), related_name='ensemble_member', on_delete=models.PROTECT)
class Instrumentation(models.Model):
name = models.CharField(max_length=100, null=True, blank=True)
class Instrument(MPTTModel):
name = models.CharField(max_length=100, null=True, blank=True)
category = models.CharField(max_length=100, null=True, blank=True)
instrumentation = models.ManyToManyField(Instrumentation, verbose_name=_('instrumentation'), related_name='instrument', blank=True)
我希望能够将EnsembleMembers仅链接到Ensemble下的仪器中可用的仪器。我将如何创建此ForeignKey关系。
例如:
共有三种工具: 小提琴, 大提琴,和 钢琴
使用这三种乐器进行演奏的实例称为“钢琴三重奏”。
称为“ Beaux Arts Trio”的合奏与乐器“ Piano Trio”链接。
“ Menahem Pressler”是“ Beaux Arts Trio”的乐团成员和钢琴家。
我想将此乐器链接到“钢琴”。钢琴是允许链接的乐器,因为它在链接到乐团的乐器中。如何在EnsembleMember模型中设置最后一个连接?
在集成和演奏之前,我希望具有以下连接。
Piano Trio (Instrumentation) --> Beaux Arts Trio (Ensemble)
^ ^
| |
| |
Piano (Instrument) --> Menahem Pressler (pianist, Ensemble Member)
Violin (Instrument) --> Daniel Guilet (violinist, Ensemble Member)
Cello (Instrument) --> Bernard Greenhouse (cellist, Ensemble Member)
答案 0 :(得分:0)
我试图查看是否可以帮助您。我遇到的问题主要有两个。
下面是我的尝试,以及我如何解释您的问题,您写的是-”“我希望能够将EnsembleMembers仅链接到Ensemble下的仪器中可用的仪器。我将如何创建此ForeignKey关系。 “
即您想将EnsembleMember(例如Mannahem Pressler)链接到您在Ensemble中预定义的乐器之一。也就是说,如果合奏是钢琴三重奏,则您有钢琴,现在您想将音乐家链接到这架钢琴。
开箱即用,我没有在Django Admin中获得编辑按钮来更改钢琴上的音乐家名称,但是您可以激活此按钮,请参阅此参考文献Django admin: how to enable add/edit buttons for many-to-many model relationships
如果有误,请发表评论:
从django.db导入模型
class Person(models.Model):
name = models.CharField(max_length=100, null=True, blank=True)
def __str__(self):
return f'{self.name}'
class Instrument(models.Model): #MPTTModel):
name = models.CharField(max_length=100, null=True, blank=True)
category = models.CharField(max_length=100, null=True, blank=True)
person = models.ManyToManyField('Person', blank=True)
def __str__(self):
return f'{self.name}'
class Instrumentation(models.Model):
name = models.CharField(max_length=100, null=True, blank=True)
instrument = models.ManyToManyField('Instrument', blank=True)
def __str__(self):
return f'{self.name}'
class Ensemble(models.Model): # Group):
name = models.CharField(max_length=100, null=True, blank=True)
instrumentation = models.ForeignKey(Instrumentation, null=True, blank=True, on_delete=models.PROTECT)
def __str__(self):
return f'{self.name}'
class EnsembleMember(models.Model):
person = models.ForeignKey(Person, on_delete=models.PROTECT)
instrument = models.ForeignKey(Instrument, null=True, blank=True, on_delete=models.PROTECT) # //This is the line in question
ensemble = models.ForeignKey(Ensemble, on_delete=models.PROTECT)
def __str__(self):
return f'{self.person}'
答案 1 :(得分:0)
怎么样?
class Ensemble(Group):
name = models.CharField(max_length=100, null=True, blank=True)
instrumentation = models.ForeignKey(Instrumentation -> Instrument, verbose_name=_('part'), related_name='ensemble_member', null=True, blank=True, on_delete=models.PROTECT)
class EnsembleMember(models.Model):
person = models.ForeignKey(Person, verbose_name=_('member'), on_delete=models.PROTECT)
ensemble = models.ForeignKey(Ensemble, verbose_name=_('ensemble'), related_name='ensemble_member', on_delete=models.PROTECT)
ensemble_member = EnsemberMember.objects.first()
instrumentation = ensemble_member.ensemble.instrumentation
答案 2 :(得分:0)
听起来您想使用数据库约束来确保您不会意外地将无效的演奏者乐器添加到合奏中。
我看不到使用Django在数据库级别执行此操作的方法。如果您想进一步采用该方法,可以查看Django 2.2+中的约束:https://docs.djangoproject.com/en/2.2/ref/models/constraints/
我个人将为EnsembleMember模型自定义模型管理器,以在应用程序代码级别验证约束。
在您的查看代码中,而不是调用...
EnsembleMember.objects.create(...)
...调用自定义模型管理器方法(有关具体示例,请参见测试案例)
EnsembleMember.objects.add_member(...)
您的models.py文件如下所示(我替换了您的models.Model子类以使测试正常工作):
class Person(models.Model):
name = models.CharField(max_length=100, null=True, blank=True)
class Instrumentation(models.Model):
name = models.CharField(max_length=100, null=True, blank=True)
class Instrument(models.Model):
name = models.CharField(max_length=100, null=True, blank=True)
category = models.CharField(max_length=100, null=True, blank=True)
instrumentation = models.ManyToManyField(
Instrumentation,
verbose_name='instrumentation',
related_name='instrument',
blank=True
)
class Ensemble(models.Model):
name = models.CharField(max_length=100, null=True, blank=True)
instrumentation = models.ForeignKey(
Instrumentation,
verbose_name='part',
related_name='ensemble_member',
null=True, blank=True,
on_delete=models.PROTECT
)
# Catch this error in the view
class InvalidInstrumentError(Exception):
pass
class EnsembleMemberManager(models.Manager):
# This custom manager enforces your business logic
def add_member(
self,
ensemble: 'Ensemble',
member: 'Person',
instrument: 'Instrument'
):
# This clause ensures that the new ensemble member plays a valid
# instrument for the ensemble's instrumentation
if not instrument in ensemble.instrumentation.instrument.all():
raise InvalidInstrumentError
# Just like EnsembleMember.objects.create
# use **kwargs if you have more properties
return self.create(
person=member,
instrument=instrument,
ensemble=ensemble
)
class EnsembleMember(models.Model):
person = models.ForeignKey(
Person,
verbose_name='member',
on_delete=models.PROTECT
)
# You want the ForeignKey to reference Instrument, not Instrumentation
# because the person plays a specific instrument and the Ensemble
# already references Instrumentation.
# Also updated the related_name so there is no duplication
instrument = models.ForeignKey(
Instrument,
verbose_name='part',
related_name='ensemble_member_instrument',
null=True,
blank=True,
on_delete=models.PROTECT
)
ensemble = models.ForeignKey(
Ensemble,
verbose_name='ensemble',
related_name='ensemble_member',
on_delete=models.PROTECT
)
# Add this line to use the custom manager.
objects = EnsembleMemberManager()
这是一个演示您的用例的测试用例。
from django.test import TestCase
from model_mommy import mommy
from instruments.models import (
Person,
Instrumentation,
Instrument,
Ensemble,
EnsembleMember,
InvalidInstrumentError,
)
class TestMrPressler(TestCase):
def test_mgr_constraint(self):
# Valid instruments
valid_instrumentation = mommy.make(Instrumentation)
piano = mommy.make(Instrument)
violin = mommy.make(Instrument)
cello = mommy.make(Instrument)
piano.instrumentation.add(valid_instrumentation)
violin.instrumentation.add(valid_instrumentation)
cello.instrumentation.add(valid_instrumentation)
# Invalid instrument
kazoo = mommy.make(Instrument)
beaux_arts_trio = mommy.make(
Ensemble,
instrumentation=valid_instrumentation
)
menahem_pressler = mommy.make(Person)
# Mr.Pressler does NOT play kazoo
with self.assertRaises(InvalidInstrumentError):
EnsembleMember.objects.add_member(
ensemble=beaux_arts_trio,
member=menahem_pressler,
instrument=kazoo
)
# But he fiddles like a beast
presslers_role = EnsembleMember.objects.add_member(
ensemble=beaux_arts_trio,
member=menahem_pressler,
instrument=violin
)
self.assertEqual(
presslers_role.instrument.name,
violin.name
)