1

これは、lat / lon FloatFields で構成される PointField を構築する方法を理解しようとしているこの質問の続きです。@Simon のアドバイスを受けて、モデルを次のように再構築しました。

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

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

私のフォームには、Google マップの経度と緯度の座標の値に対応する 2 つのフィールドがあります。

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

ただし、これは明らかな理由で機能しませんが、修正方法がわかりません。明確にするために、 と の外部キー値に対応する 2 つのフォーム フィールドを作成しようとしてい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],})

すべてのアドバイスとヘルプに感謝します!


編集:富田裕二の入力に基づいて更新します。そのほとんどは非常に理にかなっていますが (ありがとうございます!)、なぜ 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)

フォームでGoogleマップを使用し、選択した入力から緯度と経度を取得し、それらの値からポイントフィールドを構築しているため、フォームフィールドを緯度と経度のままにしておく必要があると思います。

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

1 に答える 1

3

saveデータベースに自分自身を保存する方法を知っている各フォームにメソッドを構築することをお勧めします。「フォームは form.save() を介してアクションを実行する」という一般的なパターンに従うため、直感的に従う必要があります。

肝心なのは、「すべてのフォームのすべてのフィールドについて、モノの属性をそれらのフィールドに設定する」というブランケットがあるということです。

実際にはフォームごとに保存動作があるため、各フォームにインスタンスを渡すことを要求して、各フォームがそのフィールドに適した方法でデータを保存できるようにすることは理にかなっていると思います。

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)

ただのアイデア。

それについてもっと DRY になりたい場合、および他のフォームの自動化が好きな場合は、保存メソッドが既に定義されている基本フォームを作成します。

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
于 2013-10-04T20:36:07.820 に答える