我有一个数据模型,我在其中使用手动中间表来处理 m2m 关系。基于 django 文档中的经典示例:
from django.db import models
INSTRUMENT_CHOICES = (
('guitar', 'Guitar'),
('bass', 'Bass Guitar'),
('drum', 'Drum'),
('keyboard', 'Keyboard'),
)
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Leadership')
def __str__(self):
return self.name
def get_leadership():
return self.leadership_set.first()
class Leadership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
instrument = models.CharField('Playing Instrument', choices=INSTRUMENT_CHOICES,
max_length=15,
null=True,
blank=False)
class Meta:
unique_together = ('person', 'group')
当我创建一个新组时,我还想指定谁将成为领导者,并且对于这种关系还指定他将在该组中演奏哪种乐器。
鉴于缺乏关于这个主题的文档,真正让我感到困惑的是如何处理表单中的这种关系。
这是我带来的表格:
class InstrumentField(forms.ChoiceField):
def __init__(self, *args, **kwargs):
super().__init__(INSTRUMENT_CHOICES, *args, **kwargs)
class GroupForm(forms.ModelForm):
instrument = InstrumentField(required=False)
class Meta:
model = Group
fields = ['name',
'members'
'instrument'] # This works but it's not correctly initalized in case of edit form
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance.pk is not None: # editing
# PROBLEM: this doesn't work
self.fields["instrument"].initial = self.instance.get_leadership().instrument
def save(self, commit=True):
group = super().save(commit=False)
if commit:
group.save()
if 'instrument' in self.changed_data:
leader = self.cleaned_data.get('members').first()
instrument = self.cleaned_data['instrument']
Leadership.objects.update_or_create(person=leader, group=group, defaults={'instrument': instrument})
return group
正如 django 文档中所建议的那样,我正在手动实例化Leadership
对象(请参阅 formsave
方法)。
我无法解决的是如何instrument
在表单编辑的情况下填充该字段。我尝试在 中执行此操作__init__
:首先我检查我们是否处于“编辑”模式(实例有一个 pk)然后我获取相关Leadership
对象(请参阅Group.get_leadership
)并从中提取instrument
并将其分配给fields["instrument"].initial
.
这行不通。
我可以检查该initial
值是否已设置,但是当我呈现表单时,会显示默认选择值(INSTRUMENT_CHOICES 的第一个值)。
我在这里想念什么?关于如何通过表单中的模型处理 m2m 是否有更好的方法或更好的文档?