the*_*rty 71 python django django-forms
考虑以下模型和形式:
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
Run Code Online (Sandbox Code Playgroud)
当你查看ToppingForm时,它可以让你选择浇头上的披萨,一切都只是花花公子.
我的问题是:如何定义一个ModelForm for Pizza,让我可以利用Pizza和Topping之间的多对多关系,让我选择Toppings在Pizza上的内容?
Clé*_*ent 122
我想你可以在这里添加一个新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
Run Code Online (Sandbox Code Playgroud)
这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)
Run Code Online (Sandbox Code Playgroud)
该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
Run Code Online (Sandbox Code Playgroud)
Jac*_* M. 15
我不确定我是100%得到这个问题,所以我将按照这个假设运行:
每个都Pizza可以有很多Toppings.每个都Topping可以有很多Pizzas.但是如果a Topping被添加到a中Pizza,Topping则自动地将其添加到a ,Pizza反之亦然.
在这种情况下,你最好的选择是一个关系表,Django支持得很好.它可能看起来像这样:
models.py
class PizzaTopping(models.Model):
topping = models.ForeignKey('Topping')
pizza = models.ForeignKey('Pizza')
class Pizza(models.Model):
name = models.CharField(max_length=50)
topped_by = models.ManyToManyField('Topping', through=PizzaTopping)
def __str__(self):
return self.name
def __unicode__(self):
return self.name
class Topping(models.Model):
name=models.CharField(max_length=50)
is_on = models.ManyToManyField('Pizza', through=PizzaTopping)
def __str__(self):
return self.name
def __unicode__(self):
return self.name
Run Code Online (Sandbox Code Playgroud)
forms.py
class PizzaForm(forms.ModelForm):
class Meta:
model = Pizza
class ToppingForm(forms.ModelForm):
class Meta:
model = Topping
Run Code Online (Sandbox Code Playgroud)
例:
>>> p1 = Pizza(name="Monday")
>>> p1.save()
>>> p2 = Pizza(name="Tuesday")
>>> p2.save()
>>> t1 = Topping(name="Pepperoni")
>>> t1.save()
>>> t2 = Topping(name="Bacon")
>>> t2.save()
>>> PizzaTopping(pizza=p1, topping=t1).save() # Monday + Pepperoni
>>> PizzaTopping(pizza=p2, topping=t1).save() # Tuesday + Pepperoni
>>> PizzaTopping(pizza=p2, topping=t2).save() # Tuesday + Bacon
>>> tform = ToppingForm(instance=t2) # Bacon
>>> tform.as_table() # Should be on only Tuesday.
u'<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" value="Bacon" maxlength="50" /></td></tr>\n<tr><th><label for="id_is_on">Is on:</label></th><td><select multiple="multiple" name="is_on" id="id_is_on">\n<option value="1">Monday</option>\n<option value="2" selected="selected">Tuesday</option>\n</select><br /> Hold down "Control", or "Command" on a Mac, to select more than one.</td></tr>'
>>> pform = PizzaForm(instance=p1) # Monday
>>> pform.as_table() # Should have only Pepperoni
u'<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" value="Monday" maxlength="50" /></td></tr>\n<tr><th><label for="id_topped_by">Topped by:</label></th><td><select multiple="multiple" name="topped_by" id="id_topped_by">\n<option value="1" selected="selected">Pepperoni</option>\n<option value="2">Bacon</option>\n</select><br /> Hold down "Control", or "Command" on a Mac, to select more than one.</td></tr>'
>>> pform2 = PizzaForm(instance=p2) # Tuesday
>>> pform2.as_table() # Both Pepperoni and Bacon
u'<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" value="Tuesday" maxlength="50" /></td></tr>\n<tr><th><label for="id_topped_by">Topped by:</label></th><td><select multiple="multiple" name="topped_by" id="id_topped_by">\n<option value="1" selected="selected">Pepperoni</option>\n<option value="2" selected="selected">Bacon</option>\n</select><br /> Hold down "Control", or "Command" on a Mac, to select more than one.</td></tr>'
Run Code Online (Sandbox Code Playgroud)
说实话,我会将多对多关系放入Pizza模型中.我认为这更贴近现实.想象一下,一个人订了几个比萨饼.他不会说"我想在比萨饼一和二上吃奶酪,在比萨饼一和三上吃西红柿",但可能是"一个披萨加奶酪,一个披萨加奶酪和西红柿,......".
当然可以让表单以你的方式工作,但我会选择:
class Pizza(models.Model):
name = models.CharField(max_length=50)
toppings = models.ManyToManyField(Topping)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
65642 次 |
| 最近记录: |