Django ChoiceField или TypedChoiceField и неверный выбор идентификатора

Я пишу простую форму в Django, которая включает ChoiceField, позволяющую пользователям выбирать из списка категорий. Наверняка я хочу передать category_id для обработки. Это мой код:

модели.py:

class Category(models.Model):
      category = models.CharField(max_length=128)

      def __unicode__(self):
           return self.category


class Product(models.Model):
      code = models.CharField(max_length=75)
      name = models.CharField(max_length=128)
      price = models.DecimalField(max_digits=7, decimal_places=2)
      category = models.ForeignKey(Category)

      def __unicode__(self):
           return self.name

формы.py

class AddProductForm(forms.Form):
    category = forms.ChoiceField(label=_('Category'))
    product = forms.CharField(label=_('Product'), widget=forms.TextInput())
    code = forms.CharField(label=_('Code'), widget=forms.TextInput())
    price = forms.DecimalField(label=_('Price'))

Теперь в views.py я заполняю варианты:

def add_product_form(request):
    form = AddProductForm()

    form.fields['category'].choices =[(c.id, c.category) for c in Category.objects.all()] 

    return render_to_response('product-form.html', {'form':form})

Теперь вроде бы все в порядке, за исключением случаев, когда я отправляю форму. Он жалуется на идентификаторы категории. В нем говорится: Выберите допустимый вариант. 1 не является одним из доступных вариантов

Вот как я обрабатываю форму:

def add_product(request):
   if request.method == 'POST':
       form = AddProductForm(request.POST)

       if form.is_valid():
           category = request.cleaned_data['category']
           product = form.cleaned_data['product']
           code = form.cleaned_data['code']
           price = form.cleaned_data['price']

           product = Product(code=code, name=product, price=price, category_id=category)

           product.save()

           return HttpResponseRedirect('/ms-admin/')
       else:
           form = AddProductForm() # more is required here to fill the choices again

       return render_to_response('product-form.html', {'form':form})

Я попробовал то же самое с TypedChoiceField, но получил те же недопустимые данные. Я знаю, что это связано с преобразованием между строкой и целым числом и юникодом. Не могли бы вы объяснить?


person blaise    schedule 23.10.2011    source источник


Ответы (2)


По какой-то причине вы разделили представление, отображающее форму, включая добавление вариантов, и представление, обрабатывающее отправку. Вы не добавляете варианты при отправке, поэтому, конечно, значения не будут действительными.

Вы должны полностью избавиться от представления add_product_form. Вы можете переместить бит form.fields['category'].choices... в представление add_product, но лучшим решением является использование поля формы, которое специально разработано для получения вариантов выбора из модели или набора запросов, т. е. ModelChoiceField.

Просто используйте:

category = forms.ModelChoiceField(model=Category)

в вашем определении формы.

person Daniel Roseman    schedule 23.10.2011

Спасибо Даниэль. Я начал изучать Django не так давно, и у меня есть тенденция добавлять представление для отображения формы, что не обязательно. Так что да, я избавился от add_product_form и полагался исключительно на add_product. Что касается поля выбора категории, то теперь оно закодировано в form.py следующим образом:

формы.py:

from django import forms
from django.utils.translation import ugettext_lazy as _

from myapp.models import Category

class AddProductForm(forms.Form):
    category = forms.ModelChoiceField(label=_('Category'), queryset=Category.objects.all())
    product = forms.CharField(label=_('Product'), widget=forms.TextInput())
    code = forms.CharField(label=_('Code'), widget=forms.TextInput())
    price = forms.DecimalField(label=_('Price'))

просмотров.py:

def add_product(request):
   if request.method == 'POST':
      form = AddProductForm(request.POST)

      if form.is_valid():
         category = request.POST['category']
         product = form.cleaned_data['product']
         code = form.cleaned_data['code']
         price = form.cleaned_data['price']

         product = Product(code=code, name=product, price=price, category_id=category)

         product.save()

         # redirect to 'ms-admin/category_id' (the category to which belongs the newly added product
         return HttpResponseRedirect('/ms-admin/'+category)
     else:
         form = AddProductForm()

     return render_to_response('product-form.html', {'form':form})

Надеюсь, это поможет новичкам в django. Пожалуйста, не стесняйтесь упоминать любые способы улучшения этого кода выше...

person blaise    schedule 23.10.2011