2013-10-04 70 views
1

這是this question的延續,其中我想弄清楚如何構建由經緯度FloatFields組成的PointField。我已@西蒙的建議和重組我的模型看起來像這樣:Django:從表格中保存外鍵

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

然而,這並不明顯的原因工作,但我不知道如何解決它。爲了澄清,我試圖有兩個對應於外鍵值latlon的表單字段。這裏是補充信息(我使用的是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)) 
+0

請編輯您的[原題] (http://stackoverflow.com/questions/19167076/django-filtering-queryset-from-two-model-fields)而不是分散在多個線程。 –

+0

我的理解是,如果一個問題與原始問題不同,我應該提出一個新問題。前一個問題涉及如何基於兩個獨立的模型字段進行「過濾」。它被回答了。這個主題是不同的,因爲它要求如何從表單中保存'ForeignKey'字段,這完全不同於基於兩個模型字段組合的過濾。如果我錯了,我會感謝主持人澄清。謝謝! –

+0

@NickB,你在這裏完全沒問題。閱讀帖子時,我們都會做出突然的假設。感謝您的公民! –

回答

3

我建議建立在你的每一個形成一個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. 

你的觀點將成爲:

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 
+0

哇,非常感謝,非常有幫助,並有助於進一步解釋表單中發生了什麼。謝謝!然而,我認爲我錯誤地實現了它,因爲我的嘗試導致了一個'ValueError'。如果你有一點時間,對於我可能做錯的事情得到你的意見會很酷,但如果你太忙,我也會理解。再次感謝! –

+0

@NickB,沒問題。錯誤是我的錯,get_or_create返回實例並創建或不創建標誌。你應該分配'thing.point = Point.objects.create(lat = lat,long = long)'或'thing.point = ... get_or_create()[0]' –

+0

感謝您的耐心協助。我從你的解釋中學到了很多東西,現在我能夠正確地將對象保存在FormWizard中!再次感謝! –