python - Django:从表单中保存外键

标签 python django forms foreign-keys django-formwizard

这是 this question 的延续我试图弄清楚如何构造一个由纬度/经度 FloatFields 组成的 PointField。我采纳了 @Simon 的建议并将我的模型重组为如下所示:

class Point(models.Model):
   lat = models.FloatField()
   lon = models.FloatField()

class Thing(models.Model):
   point = models.ForeignKey(Point)

我的表单有两个字段对应于谷歌地图的经度和纬度坐标值:

class StepThreeForm(forms.Form):
    lat = forms.FloatField()
    lon = forms.FloatField()
    ...

但是,由于明显的原因,这不起作用,但我不知道如何解决它。为了澄清,我试图有两个表单字段对应于 lat 的外键值。和lon 。这是补充信息(我正在使用 FormWizard 和 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],})

我感谢所有建议和帮助!

<小时/>

编辑:根据 Yuji Tomita 的输入进行更新。其中大部分都很有意义(谢谢!),但我不确定为什么它会导致 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)

我认为我应该将表单字段保留为纬度和经度,因为我在表单中使用谷歌地图并从选定的输入中获取纬度和经度,然后根据这些值构建点字段:

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: Cannot assign "(<Point: Point object>, False)": "Thing.point" must be a "Point" instance.

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))

最佳答案

我建议在每个表单上构建一个 save 方法,该方法知道如何将自身保存到数据库中。它遵循“表单通过 form.save() 执行其操作”的一般模式,因此应该很直观。

最重要的是,现在您有一个毯子:“对于所有表单中的每个字段,将 Thing 属性设置为这些字段”。

由于实际上您具有按表单保存行为,因此我认为要求将实例传递给每个表单是有意义的,以便每个表单都有机会以适合其字段的方式保存数据。

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.

您的 View 将变为:

for form in form_list:
    form.save(instance)

只是一个想法。

如果您想更加干燥,并且喜欢其他表单的自动化,我会构建一个已定义保存方法的基本表单:

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

关于python - Django:从表单中保存外键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19188908/

相关文章:

python - 递归扩展和搜索特定子目录的模式

python - Django : import problem with python-twitter module

html - 使用 perl LWP lib 传递表单数据时遇到问题

PHP 从不接收嵌套的 jQuery $.post 数据

javascript - 元素构建时触发 jQuery 更改事件

python - 理解 "Think Python"中的 turtle 圆和弧

python list/dict 属性最佳实践

python - 如何通过for循环在gekko中进行约束?

django - 保存后不立即更新多对多关系的问题

django - 使用Webpack_Loader错误将Django Dockering