Myślę, że musiałbyś tutaj dodać nowe ModelMultipleChoiceField
do swojego PizzaForm
i ręcznie połączyć to pole formularza z polem modelu, ponieważ Django nie zrobi tego automatycznie za Ciebie.
Pomocny może być następujący fragment kodu:
class PizzaForm(forms.ModelForm):
class Meta:
model = Pizza
toppings = forms.ModelMultipleChoiceField(queryset=Topping.objects.all())
def __init__(self, *args, **kwargs):
if kwargs.get('instance'):
initial = kwargs.setdefault('initial', {})
initial['toppings'] = [t.pk for t in kwargs['instance'].topping_set.all()]
forms.ModelForm.__init__(self, *args, **kwargs)
def save(self, commit=True):
instance = forms.ModelForm.save(self, False)
old_save_m2m = self.save_m2m
def save_m2m():
old_save_m2m()
instance.topping_set.clear()
instance.topping_set.add(*self.cleaned_data['toppings'])
self.save_m2m = save_m2m
if commit:
instance.save()
self.save_m2m()
return instance
To PizzaForm
może być następnie wykorzystane wszędzie, nawet w admin:
from django.contrib.admin import site, ModelAdmin
from yourapp.models import Pizza
from yourapp.forms import PizzaForm
class PizzaAdmin(ModelAdmin):
form = PizzaForm
site.register(Pizza, PizzaAdmin)
Uwaga
save()
Metoda może być nieco zbyt rozwlekły, ale można uprościć, jeśli nie trzeba wspierać commit=False
sytuację, to wtedy tak:
def save(self):
instance = forms.ModelForm.save(self)
instance.topping_set.clear()
instance.topping_set.add(*self.cleaned_data['toppings'])
return instance
Pizza
może mieć wieleTopping
s. KażdyTopping
może mieć wielePizza
s. Ale jeśli dodam aTopping
do aPizza
, czy toPizza
wtedy automagicznie ma aTopping
i odwrotnie?