Django ModelForm用于多对多字段
考虑以下模型和形式:
class Pizza(models.Model): name = models.CharField(max_length=50)
class Topping(models.Model):
name = models.CharField(max_length=50)
ison = models.ManyToManyField(Pizza, blank=True)
class ToppingForm(forms.ModelForm):
class Meta:
model = Topping
当你查看ToppingForm时,它使你可以选择浇头所用的披萨,而一切都太花哨了。
我的问题是:如何为披萨定义一个ModelForm,让我利用披萨和馅料之间的多对多关系,并让我选择披萨上的馅料?
回答:
我想你会在这里新添加ModelMultipleChoiceField
到你PizzaForm
,并手动链接,表单字段与模型领域,如Django会不会为你做自动。
以下代码段可能会有所帮助:
class PizzaForm(forms.ModelForm): class Meta:
model = Pizza
# Representing the many to many related field in Pizza
toppings = forms.ModelMultipleChoiceField(queryset=Topping.objects.all())
# Overriding __init__ here allows us to provide initial
# data for 'toppings' field
def __init__(self, *args, **kwargs):
# Only in case we build the form from an instance
# (otherwise, 'toppings' list should be empty)
if kwargs.get('instance'):
# We get the 'initial' keyword argument or initialize it
# as a dict if it didn't exist.
initial = kwargs.setdefault('initial', {})
# The widget for a ModelMultipleChoiceField expects
# a list of primary key for the selected data.
initial['toppings'] = [t.pk for t in kwargs['instance'].topping_set.all()]
forms.ModelForm.__init__(self, *args, **kwargs)
# Overriding save allows us to process the value of 'toppings' field
def save(self, commit=True):
# Get the unsave Pizza instance
instance = forms.ModelForm.save(self, False)
# Prepare a 'save_m2m' method for the form,
old_save_m2m = self.save_m2m
def save_m2m():
old_save_m2m()
# This is where we actually link the pizza with toppings
instance.topping_set.clear()
instance.topping_set.add(*self.cleaned_data['toppings'])
self.save_m2m = save_m2m
# Do we need to save all changes now?
if commit:
instance.save()
self.save_m2m()
return instance
这PizzaForm
然后可以使用无处不在,甚至在admin:
# yourapp/admin.pyfrom 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)
注意
该save()
方法可能有点过于冗长,但是如果你不需要支持这种commit=False
情况,则可以将其简化,如下所示:
def save(self): instance = forms.ModelForm.save(self)
instance.topping_set.clear()
instance.topping_set.add(*self.cleaned_data['toppings'])
return instance
以上是 Django ModelForm用于多对多字段 的全部内容, 来源链接: utcz.com/qa/419617.html