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.py

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)

注意

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

回到顶部