2010-03-04 12 views
2

我們有一個Django模型,ToolDataset和一個ModelForm,ToolForm。在Model中,每個實例或數據庫行稱爲數據集,主鍵稱爲dataset_id。第一次通過時,用戶填寫一個未綁定的表單並提交。從概念上講,這是用來驗證,保存和分析數據集的視圖代碼:爲什麼已知有效的Django模型實例在從數據庫檢索後失敗is_valid()?

if (request.method == 'POST') and (not dataset_id): 
    form = ToolForm(request.POST) 
    if form.is_valid(): 
     new_dataset = form.save() 
     dataset_id = new_dataset.pk 
     results = analyze(form.cleaned_data) 
    else: 
     <validation error code> 

我認爲到目前爲止,這是非常正常的。請注意,表單數據不會保存,除非數據有效,否則不會分配dataset_id。

現在過了一段時間,用戶想要返回到這個特定的舊數據集,也許要更改數據並重新分析它。所以,無論如何,一個網址的構成看起來像www.finesite.com/Tool/X/,其中X是與用戶想要使用的特定行數據對應的dataset_id。通過URL配置,視圖代碼的不同分支被調用時,我們認爲應該是這樣的:

if (request.method != 'POST') and (dataset_id): 
    oldset = get_object_or_404(ToolDataset, pk=dataset_id) 
    form = ToolForm(instance=oldset) 
    if form.is_valid(): 
     results = analyze(form.cleaned_data) 
    else: 
     <validation error code that we expected would never run> 

嗯,事實證明,這個數據集,這是有效的,當我們保存它,沒有按」現在驗證,這是一個驚喜。我們使用manage.py shell來檢查表單。下面是一些我們發現:

>>> form.is_valid() 
False 
>>> form.errors 
{} 
>>> form.non_field_errors() 
[] 
>>> form.is_bound 
False 

運行form.as_p()產生什麼似乎是一個完整的形式。

一個非常能幹的人在django/forms/models.py中找到了一個未公開的API函數,稱爲model_to_dict()。他建議代位,

form = BXEEP_L_Form(model_to_dict(oldset), instance=oldset), 

爲此,

form = BXEEP_L_Form(instance=oldset). 

它現在 - 的形式是有效的,裝訂成冊,根據外殼 - 但我滿腹的疑問。爲什麼這個工作?爲什麼這是必要的?有沒有更標準的方法來做到這一點?看起來很常見並且不復雜的用例中使用未公開的內部函數似乎很奇怪。

回答

1

我可能誤解了一些東西,但在我看來,analyze函數不應該把form.cleaned_data作爲輸入,而是dataset_id

如果示例沒有完成 - 爲什麼要從數據集創建表單以便分析它?

+0

如果我使用dataset_id作爲我的分析函數的參數,那將是一個小得多的參數來傳遞,但然後分析函數需要做一個數據庫查詢,並且我認爲這樣做的最終結果是要減慢事情下降了一點。真正控制整個過程的視圖使用get_object_or_404來部分獲取這些數據,以便將其呈現給頁面。由於這些數據已經存在,爲什麼要查詢數據庫兩次。爲什麼不把它傳遞給analyze()? – 2010-03-04 15:28:32

+0

數據集包含工程設計問題的參數。當用戶經過一段時間後返回數據集時,可能是因爲他想要優化設計(調整參數)或者只是查看舊的結果。無論哪種情況,都必須再次進行分析,以便通過一系列計算的性能測量(稱爲統一檢查)來查看設計的當前狀態,這些測量不會保存,因此在重新計算之前無法顯示分析功能。 – 2010-03-04 15:31:26

+0

我現在看到了你的第一點的含義。最好的想法是將分析函數的參數作爲模型實例,而不是form.cleaned_data。然後分析函數可以繼續,而is_valid()不必再次運行。 is_valid()用於驗證用戶輸入,因此它在這裏的使用是不必要的,因爲這是在前面完成的。除了一些重寫之外,這個改變沒有任何缺點。見下文。 – 2010-03-04 19:02:39

3

form.is_valid()驗證form.data字典,這是通過構造用於發送Form(data=request.POST)

ModelForm.instance數據與特定的表相關聯的行,以使得一個保存一定執行更新,而不是一個插入件。這也通過構造函數傳遞。

然而,這兩者都是彼此獨立的。如果你想創建一箇舊實例的數據表格,你應該做到以下幾點:

ToolForm(data=oldinstance.__data__, instance=oldinstance) 

然而,你也許真的不希望將數據綁定的時候了。

ToolForm(instance=oldinstance) 

從實例填充正確的價值觀,當HTML渲染和更新記錄,只有當TOOLFORM例如is_changed()

+0

似乎很奇怪,form = ToolForm(instance = oldset)不會產生可以使用is_valid()檢查的表單。不過,我接受你說的話。 我想你的意思是__dict__,而不是__data__。在模型實例中使用__dict__會引起一些新的複雜問題(請參見:http://www.google.com/url?q=http://docs.djangoproject.com/zh/dev/releases/1.2-alpha-1 /%23dict-on-model-instances&usg = AFQjCNGcuOScV33WhD6ww1d7AK-BwVyfSA&ei = hgaQS5j7G4j6sgOd8eS5CA&sa = X&oi = section_link&resnum = 1&ct = legacy。)可能會使model_to_dict成爲更好的選擇。 – 2010-03-04 19:19:29

0

我們改變了分析功能,是一個模型實例,而不是形式的參數.cleaned_data。這從表單驗證分析中分離出來,並且更合理。從概念上講,現在上面給出的代碼的第二部分,現在看起來是這樣的:

if (request.method != 'POST') and (dataset_id): 
     oldset = get_object_or_404(ToolDataset, pk=dataset_id) 
     form = ToolForm(instance=oldset) 
     results = analyze(oldset) 

當然,數據的分析函數的開始拆包不得不有所重寫。

現在這一切似乎很明顯。謝謝大家,感謝您的關注!

相關問題