2011-12-29 112 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