Django:从表单中保存外键 [英] Django: Saving Foreign Key from Form
问题描述
这是这个问题的延续,我在其中试图找出如何构造一个由lat / lon FloatField组成的PointField。我已经采取@ Simon的建议,并重新组建了我的模型,如下所示:
This is a continuation of this question in which I am trying to figure out how to construct a PointField composed of lat / lon FloatFields. I have taken @Simon's advice and restructured my model to look like this:
class Point(models.Model):
lat = models.FloatField()
lon = models.FloatField()
class Thing(models.Model):
point = models.ForeignKey(Point)
我的表单有两个字段对应于谷歌地图的经度和纬度坐标值:
My form has two fields corresponding to values from google maps' longitude and latitude coordinates:
class StepThreeForm(forms.Form):
lat = forms.FloatField()
lon = forms.FloatField()
...
但是,由于明显的原因,这不起作用,但我不知道如何修理它。为了澄清,我试图有两个表单域对应于 lat
和 lon
的外键值。以下是补充信息(我使用FormWizard和forms.Form):
However, this does not work for obvious reasons, but I am not sure how to fix it. To clarify, I am trying to have two form fields corresponding to the foreign key values of lat
and lon
. Here is the supplementary information (I am using a FormWizard and forms.Form):
url(r'^mapform/$', login_required(MyWizard.as_view([StepOneForm, StepTwoForm, StepThreeForm])), name='create'),
class MyWizard(SessionWizardView): ## this view also serves to edit existing objects and provide their instances
def done(self, form_list, **kwargs):
id = form_list[0].cleaned_data['id']
try:
thing = Thing.objects.get(pk=id)
instance = thing
except:
thing = None
instance = None
if thing and thing.user != self.request.user:
raise HttpResponseForbidden()
if not thing:
instance = Thing()
for form in form_list:
for field, value in form.cleaned_data.iteritems():
setattr(instance, field, value)
instance.user = self.request.user
instance.save()
return render_to_response('wizard-done.html', {
'form_data': [form.cleaned_data for form in form_list],})
感谢任何和所有的建议和帮助!
I appreciate any and all advice and help!
编辑:基于Yuji Tomita的输入更新。大多数情况很有意义(谢谢!),但我不知道为什么会导致ValueError。
Update based on Yuji Tomita's input. Most of it made a lot of sense (Thank you!), but I'm not sure why it results in a ValueError.
class MyWizard(SessionWizardView):
....
for form in form_list:
form.save(instance)
...
class StepOneForm(forms.Form):
...
def save(self, thing):
for field, value in self.cleaned_data.items():
setattr(thing, field, value)
class StepTwoForm(forms.Form):
...
def save(self, thing):
for field, value in self.cleaned_data.items():
setattr(thing, field, value)
我相信我应该把表单字段保持为lat和lon,因为我以我的形式使用谷歌地图,从选定的输入中,然后从这些值构造一个点字段:
I believe that I should keep the form fields as lat and lon, because I am using a google map in my form and taking the lat and lon from a selected input, then constructing a point fields from those values:
class StepThreeForm(forms.Form):
lat = forms.FloatField()
lon = forms.FloatField()
def save(self, thing):
thing.point = Point.objects.get_or_create(lat=self.cleaned_data.get('lat'), lon=self.cleaned_data.get('lon'))
这将产生一个 ValueError:无法分配(< Point:Point对象> False):Thing.point必须是Point实例。
Traceback:
File "/lib/python2.7/django/core/handlers/base.py" in get_response
111. response = callback(request, *callback_args, **callback_kwargs)
File "/lib/python2.7/django/contrib/auth/decorators.py" in _wrapped_view
20. return view_func(request, *args, **kwargs)
File "/lib/python2.7/django/views/generic/base.py" in view
48. return self.dispatch(request, *args, **kwargs)
File "/lib/python2.7/django/contrib/formtools/wizard/views.py" in dispatch
223. response = super(WizardView, self).dispatch(request, *args, **kwargs)
File "/lib/python2.7/django/views/generic/base.py" in dispatch
69. return handler(request, *args, **kwargs)
File "/lib/python2.7/django/contrib/formtools/wizard/views.py" in post
286. return self.render_done(form, **kwargs)
File "/lib/python2.7/django/contrib/formtools/wizard/views.py" in render_done
328. done_response = self.done(final_form_list, **kwargs)
File "/myproject/myapp/forms.py" in done
93. form.save(instance)
File "/myproject/myapp/forms.py" in save
67. thing.point = Thing.objects.get_or_create(lat=self.cleaned_data.get('lat'), lon=self.cleaned_data.get('lon'))
File "/lib/python2.7/django/db/models/fields/related.py" in __set__
366. self.field.name, self.field.rel.to._meta.object_name))
推荐答案
我建议建立一个 code>方法,您知道如何将自己保存到数据库中。它遵循一般的模式,即表单通过form.save()执行其操作,所以应该直观地遵循。
I'd recommend building a save
method on each of your forms which knows how to save itself to the database. It follows a general pattern that "the form performs its action via form.save()" so it should be intuitive to follow.
底线是现在你有一个毯子:对于所有形式的每个字段,将Thing属性设置为这些字段。
The bottom line is that right now you have a blanket: "for every field in all forms, set the Thing attribute to those fields".
由于实际上您具有每个表单的保存行为,我认为需要将实例传递给每个表单是有意义的,因此每个表单都有机会将数据保存在适用于其字段的方式。
Since in reality you have per-form save behavior, I think it makes sense to require passing the instance to each form so that each form has a chance to save data in the way appropriate for its fields.
class Form1(...):
def save(self, thing):
for field, value in self.cleaned_data.items():
setattr(thing, field, value)
class Form2(...):
def save(self, thing):
thing.point = Point.objects.get_or_create(lat=self.cleaned_data.get('lat'), long=...)
# note, you may not want get_or_create if you don't want to share points.
您的观点将变为:
for form in form_list:
form.save(instance)
只是一个想法。
如果你想更加干涩,像其他表单的自动化一样,我会建立一个基础表单,它有一个已经定义的保存方法:
If you want to be more DRY about it and like the automation of your other forms, I'd build a base form which has a save method already defined:
class BaseSaveBehaviorForm(forms.Form):
def save(self, thing):
for field, value in self.cleaned_data.items():
setattr(thing, field, value)
class NormalBehaviorForm(BaseSaveBehaviorForm):
# your forms as usual
class SpecialSaveBehaviorForm(forms.Form):
def save(self, instance):
# do something unusual
这篇关于Django:从表单中保存外键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!