2011-12-29 114 views
2

我正在處理按類別分組的分類目錄。無法使用ChoiceField檢查表單值

然而,當我提出我的形式,我得到了以下錯誤消息:

Caught ValueError while rendering: Cannot assign "u'9'": "Classified.category" must be a "Category" instance. 

我相信這是因爲Django的期望一個類別對象,而不是一個簡單的整數對應於所選擇的類別ID。

下面是我如何編寫系統: 分類鏈接到一個類別。 類別系統是分層次的,具有父類別和子類別列表。 例如,我有這樣的事情:

Electronics 
    |-- IPad 
    |-- IPods 
    |-- ... 

所以我有以下型號:

class Category(BaseModel): 
    # [...] 
    name = models.CharField(u'Name', max_length=50) 
    slug = AutoSlugField(populate_from='name', slugify=slugify, unique=True, 
     unique_with='name', max_length=255, default='') 
    parent = models.IntegerField(u'parent', max_length=10, null=False, 
      default=0) 

    objects = CategoryManager() 

    # [...] 

class Classified(BaseModel): 
    # [...] 
    category = models.ForeignKey(Category, related_name='classifieds') 

我創建了以下管理員:

class CategoryManager(Manager): 
    def categoryTree(self): 
     tree = self.raw("SELECT" 
      " P.id, P.name parent_name, P.slug parent_slug, P.id parent_id," 
      " C.name child_name, C.slug child_slug, C.id child_id" 
      " FROM classified_category C" 
      " LEFT JOIN classified_category P ON P.id = C.parent" 
      " WHERE C.parent <> 0" 
      " ORDER BY P.name, C.name;") 

     categoryTree = [] 

     current_parent_id = tree[0].parent_id 
     current_parent_name = tree[0].parent_name 
     option_list = [] 

     for c in tree: 
      if current_parent_id != c.parent_id: 
       categoryTree.append((current_parent_name, option_list)) 
       option_list = [] 
       current_parent_id = c.parent_id 
       current_parent_name = c.parent_name 

      option_list.append((c.child_id, c.child_name)) 

     categoryTree.append((current_parent_name, option_list)) 

     return category 

我的Django的形式包含以下:

class ClassifiedForm(forms.ModelForm): 
    # [...] 

    category = forms.ChoiceField(label=u'Category', required=True, 
      choices=Category.objects.categoryTree(), widget=forms.Select()) 
    # [...] 

如果我使用category = forms.ModelChoiceField(Category.objects.all()),一切正常,但我需要控制如何顯示<select>字段與列表<optgroup>。這就是爲什麼使用categoryTree() 但不幸的是使用CategoryManager.categoryTree()打破了我的表單驗證,我不知道如何解決我的問題。

如果我可以指出我錯在哪裏以及如何解決這個問題,那就太棒了。

在此先感謝您的幫助。

+0

添加了python標籤。 – lig 2011-12-29 12:12:30

回答

1

快速解決方法是保存類別手動

class ClassifiedForm(forms.ModelForm): 
    # [...] 

    category = forms.ChoiceField(label=u'Category', required=True, 
      choices=Category.objects.categoryTree(), widget=forms.Select()) 

    class Meta: 
     exclude=('category',) 

    def save(self): 
     classified = super(ClassifiedForm, self).save(commit=False) 
     classified.category = Category.objects.get(id=self.cleaned_data['category']) 
     classified.save() 
     return classified 
0

您可以而且應該仍然使用ModelChoiceField。選擇列表可以在窗體類的初始化方法被修改 - 即

class ClassifiedForm(forms.ModelForm): 
    def __init__(self, *args, **kwargs): 
     super(ClassifiedForm, self).__init__(*args, **kwargs) 

     # Set the queryset for validation purposes. 
     # May not be necessary if categoryTree contains all categories 
     self.fields['category'].queryset = Category.objects.categoryTreeObjects() 

     # Set the choices 
     self.fields['category'].choices = Category.objects.categoryTree() 

此外,你應該仔細的django-mptt包看。看起來你可能會在這裏重新發明輪子。

+0

如果'categoryTree()'返回queryset,它可以工作。但事實並非如此。 – DrTyrsa 2011-12-29 12:50:48

+0

從他發佈的內容中,categoryTree返回一組選項。正如你所看到的,我將它分配給類別字段的選項屬性。我發明了另一個函數(他需要編寫),稱爲categoryTreeObjects,用於查詢集屬性。 – 2011-12-29 12:53:52

+0

好吧,它可以工作,但是兩個「並行」功能並不是維護的最佳選擇。而BTW'queryset' attr不僅僅用於驗證目的,'save'邏輯也很大程度上依賴於它。這就是爲什麼我不喜歡'ModelForm'。 – DrTyrsa 2011-12-29 12:59:22