2012-04-20 107 views
1

我有一個用於高級搜索的表單。其中一個字段island_group是一個ModelChoiceField,爲此我返回一個values_list作爲查詢集(以便只獲取一次不同的值)。Django在ModelChoiceField上形成keyerror

forms.py:

class SearchForm(forms.Form): 
    ... 
    island_group = forms.ModelChoiceField(
     required=False, 
     queryset=Locality.objects.values_list('islandgroup', flat=True).distinct('islandgroup') 
    ... 

因爲這將引發沿invalid choice行的錯誤,因爲我使用的值,而不是對象,我重寫了錯誤:

def clean(self): 
     cleaned_data = super(SearchForm, self).clean() 

     if self._errors["island_group"]: 
      del self._errors["island_group"] 

     return cleaned_data 

但是,我不斷收到KeyError at /collections/ 'island_group'錯誤。實際上,這些數據是從一個只讀數據庫中提取的,我只是希望能夠以最小的麻煩將它傳遞給視圖。

任何幫助將不勝感激。另外,這裏是回溯:

Traceback: 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response 
    111.       response = callback(request, *callback_args, **callback_kwargs) 
File "/home/sam/django-projects/datazone/bin/datazone/cdrs/views.py" in cdrs_index 
    59.  return render(request, 'cdrs_index.html', context)  
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/shortcuts/__init__.py" in render 
    44.  return HttpResponse(loader.render_to_string(*args, **kwargs), 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/template/loader.py" in render_to_string 
    188.   return t.render(context_instance) 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/template/base.py" in render 
    123.    return self._render(context) 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/test/utils.py" in instrumented_test_render 
    57.  return self.nodelist.render(context) 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/template/base.py" in render 
    744.     bits.append(self.render_node(node, context)) 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/template/base.py" in render_node 
    757.   return node.render(context) 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/template/loader_tags.py" in render 
    127.   return compiled_parent._render(context) 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/test/utils.py" in instrumented_test_render 
    57.  return self.nodelist.render(context) 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/template/base.py" in render 
    744.     bits.append(self.render_node(node, context)) 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/template/base.py" in render_node 
    757.   return node.render(context) 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/template/loader_tags.py" in render 
    64.    result = block.nodelist.render(context) 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/template/base.py" in render 
    744.     bits.append(self.render_node(node, context)) 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/template/base.py" in render_node 
    757.   return node.render(context) 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/template/defaulttags.py" in render 
    227.     nodelist.append(node.render(context)) 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/template/base.py" in render 
    792.    output = self.filter_expression.resolve(context) 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/template/base.py" in resolve 
    510.     obj = self.var.resolve(context) 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/template/base.py" in resolve 
    653.    value = self._resolve_lookup(context) 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/template/base.py" in _resolve_lookup 
    683.       current = getattr(current, bit) 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/forms/forms.py" in _errors 
    415.   return self.form.errors.get(self.name, self.form.error_class()) 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/forms/forms.py" in _get_errors 
    112.    self.full_clean() 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/forms/forms.py" in full_clean 
    268.   self._clean_form() 
File "/home/sam/django-projects/datazone/local/lib/python2.7/site-packages/django/forms/forms.py" in _clean_form 
    296.    self.cleaned_data = self.clean() 
File "/home/sam/django-projects/datazone/bin/datazone/cdrs/forms.py" in clean 
    113.   if self._errors["island_group"]: 

Exception Type: KeyError at /collections/ 
Exception Value: 'island_group' 

回答

0

更新

我想我知道你的例外,它可能看起來像Select a valid choice. That choice is not one of the available choices.吧? 原因是您傳遞給queryset=Locality.objects.values_list('islandgroup', flat=True).distinct('islandgroup')ValuesListQuerySet而不是QuerySetValueListQuerySet實例不包含_meta信息並用作普通列表,這會導致ModelChoiceField生成不正確的表單選項。就像下面

>>> from django import forms 
>>> from django.contrib.auth.models import * 

>>> class F(forms.Form): 
...  user = forms.ModelChoiceForm(queryset=User.objects.values_list('username', flat=True)) 

>>> print F().as_p() 
<p><label for="id_user">User:</label> <select name="user" id="id_user"> 
<option value="" selected="selected">---------</option> 
<option value="okm">okm</option> 
</select></p> 

的人爲的例子。然而,第二個選項的正確值應該是用戶OKM的pk,就像

>>> class F(forms.Form): 
...  user = forms.ModelChoiceForm(queryset=User.objects) 

>>> print F().as_p() 
<p><label for="id_user">User:</label> <select name="user" id="id_user"> 
<option value="" selected="selected">---------</option> 
<option value="1">okm</option> 
</select></p> 

因此,您需要更改island_group =線在你的代碼,根據islandgroup模型字段的類型。

除了上面的問題,你的代碼是好的。因此,如果self._errors中沒有其他'island_group'驗證錯誤,則self._errors["island_group"]會引發KeyError錯誤。

+0

因此,當我刪除我的自定義清理方法時,彈出'invalid choice'錯誤。如果在該字段中沒有選擇任何內容,那麼該字段將通過驗證,只要我選擇了某個內容,就會發生錯誤。我猜這是因爲這些是字符串值而不是對象?所以基本上我只是需要Django來阻止我失敗,因爲它們不是對象,自定義清理方法是我想到的最好的方法。我不確定我是否理解你的第三段 - 爲什麼要檢查self._errors [「island_group」]是否存在引發KeyError? – 2012-04-20 15:36:38

+0

@達爾文科技我的意思是'KeyError'是一個Python異常,就像'{} ['key']'引發的異常一樣。你可以通過{} .get('key')'或'if'key'來避免它{}:{} ['key']' – okm 2012-04-20 15:53:29

+0

OK。這適用於自定義清理方法:'self._errors:del self._errors [「island_group」]''中的if「island_group」。我想發佈'無效選擇'驗證錯誤的堆棧跟蹤 - 當Django沒有失敗時它怎麼才能訪問它(它只是返回那個錯誤)? – 2012-04-20 16:07:02