Джанго использовать многие ко многим с помощью в форме
У меня есть модель данных, где я использую промежуточную таблицу вручную для отношения m2m. Основываясь на классическом примере из Django Doc:
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 doc, я вручную создаю экземпляр Leadership
объекты (см. форму save
метод).
То, что я не мог решить, как заполнить instrument
поле в случае редактирования формы. Я пытаюсь сделать это в __init__
: сначала я проверяю, что мы находимся в режиме "редактирования" (экземпляр имеет pk), затем я получаю соответствующий Leadership
объект (см. Group.get_leadership
) и из этого я извлекаю instrument
и я назначаю его fields["instrument"].initial
,
Это не работает
Я мог бы проверить, что initial
значение было установлено, но затем, когда я отображаю форму, отображается значение выбора по умолчанию (первое значение INSTRUMENT_CHOICES).
Что мне здесь не хватает? Есть ли лучший способ или лучшие документы о том, как обрабатывать m2m с помощью сквозной модели в формах?