[英]What are the steps to make a ModelForm work with a ManyToMany relationship with an intermediary model in Django?
For now, when I try to save the m2m data, it just dies and says I should use the ClientGroupe Manager...so what's missing? 现在,当我尝试保存m2m数据时,它就死了,并说我应该使用ClientGroupe Manager ...那么缺少什么?
class Groupe(models.Model):
nom = models.CharField(max_length=1500, blank=True)
class Client(models.Model):
nom = models.CharField(max_length=450, blank=True)
prenom = models.CharField(max_length=450, blank=True)
groupes = models.ManyToManyField(Groupe, null = True, blank = True, through='ClientGroupe')
class ClientGroupe(models.Model):
client = models.ForeignKey(Client)
groupe = models.ForeignKey(Groupe)
dt = models.DateField(null=True, blank=True) # the date the client is using its group's free rental rate
class Meta:
db_table = u'clients_groupes'
def modifier(request, id):
client = Client.objects.get(id=id)
form = ClientForm(instance = client)
dict = {
"form": form
, "instance" : client
}
if request.method == "POST":
form = ClientForm(request.POST, instance = client)
if form.is_valid():
client_mod = form.save()
id = client_mod.id
return HttpResponseRedirect(
"/client/%(id)s/?err=success" % {"id" : id}
)
else:
return HttpResponseRedirect(
"/client/%(id)s/?err=warning" % {"id" : id}
)
return render_to_response(
"client/modifier.html"
, dict
, context_instance=RequestContext(request)
)
EDIT : 编辑 :
and here's the ClientForm code: 这是ClientForm代码:
class ClientForm(ModelForm):
class Meta:
model = Client
EDIT #2 : here's the error message: 编辑#2 :这是错误信息:
AttributeError at /client/445/
Cannot set values on a ManyToManyField which specifies an intermediary model. Use ClientGroupe's Manager instead.
Request Method: POST
Request URL: http://localhost/client/445/
Exception Type: AttributeError
Exception Value: Cannot set values on a ManyToManyField which specifies an intermediary model. Use ClientGroupe's Manager instead.
Exception Location: C:\Python25\lib\site-packages\django\db\models\fields\related.py in __set__, line 574
Python Executable: C:\xampp\apache\bin\apache.exe
Python Version: 2.5.2
If you use the save method right now, Django will try to save using the manager (which Django doesn't allow). 如果你现在使用save方法,Django将尝试使用管理器(Django不允许)进行保存。 Unfortunately, the behavior you want is a little bit trickier than what
ModelForm
does by default. 不幸的是,你想要的行为比
ModelForm
默认的ModelForm
有点棘手。 What you need to do is create a formset . 您需要做的是创建一个formset 。
First of all, you will need to change the options of your ClientForm
so that it doesn't display the groupes
attribute. 首先,您需要更改
ClientForm
的选项,以便它不显示groupes
属性。
class ClientForm(ModelForm):
class Meta:
model = Client
exclude = ('groupes',)
Next, you must change the view to display the formset: 接下来,您必须更改视图以显示formset:
from django.forms.models import inlineformset_factory
def modifier(request, id):
client = Client.objects.get(id=id)
form = ClientForm(instance = client)
# Create the formset class
GroupeFormset = inlineformset_factory(Client, Groupe)
# Create the formset
formset = GroupeFormset(instance = client)
dict = {
"form": form
, "formset" : formset
, "instance" : client
}
if request.method == "POST":
form = ClientForm(request.POST, instance = client)
formset = GroupeFormset(request.POST, instance = client)
if form.is_valid() and formset.is_valid():
client_mod = form.save()
formset.save()
id = client_mod.id
return HttpResponseRedirect(
"/client/%(id)s/?err=success" % {"id" : id}
)
else:
return HttpResponseRedirect(
"/client/%(id)s/?err=warning" % {"id" : id}
)
return render_to_response(
"client/modifier.html"
, dict
, context_instance=RequestContext(request)
)
And obviously, you must also tweak your template to render the formset. 显然,您还必须调整模板以呈现formset。
If you need any other advice on formsets, see these articles: 如果您需要有关formset的任何其他建议,请参阅以下文章:
…
if form.is_valid():
client_mod = form.save(commit=False)
client_mod.save()
for groupe in form.cleaned_data.get('groupes'):
clientgroupe = ClientGroupe(client=client_mod, groupe=groupe)
clientgroupe.save()
…
You probably need to remove the ManyToMany field from your Client model, or else carefully exclude it from your form. 您可能需要从客户端模型中删除ManyToMany字段,否则请小心地将其从表单中排除。 Unfortunately, the default widget for the ManyToMany field cannot populate the ClientGroupe Model properly (even if the missing field, dt, had been set to autonow=True).
遗憾的是,ManyToMany字段的默认小部件无法正确填充ClientGroupe模型(即使缺少的字段dt已设置为autonow = True)。 This is something you'll either need to break out into another form, or handle in your view.
这是你需要突破到另一种形式,或在你的视图中处理。
When you save your form, you save Client object. 保存表单时,保存客户端对象。 Now if you want to assign client to the group you should do this:
现在,如果要将客户端分配给组,则应执行以下操作:
clientgroupe = ClientGroupe.objects.create(client=client_instance, groupe=groupe_instance, dt=datetime.datetime.now())
where client_instance and groupe_instance your client and groupe objets. 其中client_instance和groupe_instance您的客户和groupe objets。
I'm providing an alternative solution due to issues I encountered with forms_valid not being called: 由于我没有调用forms_valid遇到的问题,我正在提供替代解决方案:
class SplingCreate(forms.ModelForm):
class Meta:
model = SplingModel
fields = ('Link', 'Genres', 'Image', 'ImageURL',)
def save(self, commit=True):
from django.forms.models import save_instance
if self.instance.pk is None:
fail_message = 'created'
else:
fail_message = 'changed'
fields = set(self._meta.fields) - set(('Genres',))
instance = save_instance(self, self.instance, fields,
fail_message, commit, construct=False)
genres = self.cleaned_data.get('Genres')
for genre in genres:
SplingGenreModel.objects.get_or_create(spling=instance, genre=genre)
return instance
I've copied the logic from djangos forms/models.py, my field Genres is a manytomany with an intermediary table - I exclude it from the save_instance and then save it separately. 我已经从djangos forms / models.py中复制了逻辑,我的字段Genres是一个带有中间表的多种语言 - 我将它从save_instance中排除,然后单独保存。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.