views:

39

answers:

2

This question is related to this one

http://stackoverflow.com/questions/3340498/remove-all-the-elements-in-a-foreign-key-select-field

I had a foreign key field in my model which was getting pre-populated by its data and I wanted the select list to be empty. I did achieve that but the validation fails when I submit the form.

The error says "Select a valid choice option. 1 is not one of the available choices).

These are my models

class RecipeIngredient(models.Model):
    recipe = models.ForeignKey(Recipe)
    ingredient = models.ForeignKey(Ingredient)
    serving_size = models.ForeignKey(ServingSize)
    quantity = models.IntegerField()
    order = models.IntegerField()
    created = models.DateTimeField(auto_now_add = True)
    updated = models.DateTimeField(auto_now = True)

class RecipeIngredientForm(forms.ModelForm):
    serving_size = forms.ChoiceField(widget=forms.Select())

    class Meta:
        serving_size  = forms.ChoiceField(widget=forms.Select())
        model = RecipeIngredient
        fields = ('ingredient', 'quantity', 'serving_size')
        widgets  = {
            'ingredient': forms.TextInput(attrs={'class' : 'recipe_ingredient'}),
            'quantity': forms.TextInput(),
            'serving_size' : forms.Select(attrs={'class' : 'ddl'}),
        }

I get an error on the third line

recipeIngredients = models.RecipeIngredientFormSet(request.POST)
print(recipeIngredients.errors)
objRecipeIngredients = recipeIngredients.save(commit=False)

I want the select box to be empty because it gets populated by an ajax call. Any ideas what to do so the model passes the validation?

EDIT

Serving Size Model

class ServingSize(models.Model):
    name = models.CharField(max_length = 255)
    unit = models.CharField(max_length = 125)
    food_group = models.ForeignKey(FoodGroup)
    created = models.DateTimeField(auto_now_add = True)
    updated = models.DateTimeField(auto_now = True)

    objects = models.Manager()
    dal_objects = ServingSizeManager()

    def __unicode__(self):
        return self.name;
A: 

Looks like you want a ModelChoiceField, which

Allows the selection of a single model object, suitable for representing a foreign key

Alex Martelli
If I use a ModelChoiceField, I would have to provide a queryset and I am trying to avoid that. Is there a way to not provide the queryset?
iHeartDucks
@iHeartDucks, no, I don't believe you can make a `ModelChoiceField` without a queryset, but what's wrong with just using `ServingSize.objects.all()`? Unless your concept of "serving size" is really weird, there shouldn't be that many items there anyway!-)
Alex Martelli
The serving sizes can changes based on the ingredients selected. I actually populate the serving sizes after the ingredient is selected.
iHeartDucks
A: 

First, why do you have serving_size in the Meta class?

I would use an extra field in the ModelForm and leave out serving_size field altogether.

class RecipeIngredientForm(forms.ModelForm):
    mycustomfield = forms.ChoiceField(widget=forms.Select())

    class Meta:
        model = RecipeIngredient
        exclude = ('serving_size', 'created', 'updated') #etc

Then in the view I would manipulate the form to assign a valid ServingSize to the serving_size field.

[EDIT]

Alright, your actual implementation will depend on what you are pulling through ajax and how. But see the following code: -

Your form: -

class CustomRecipeIngredientForm(forms.ModelForm):
    recipe = forms.ModelChoiceField(            Recipe.objects.all(),
                                                widget=forms.Select(attrs={'class':'customclass',}))

    ingredient = forms.ModelChoiceField(        Ingredient.objects.all(),
                                                widget=forms.Select(attrs={'class':'recipe_ingredient',}))

    my_custom_serving_size_field = forms.ChoiceField(widget=forms.Select(attrs={'class':'ddl',}))

    quantity = forms.IntegerField()

    order = forms.IntegerField()

    class Meta:
        model = RecipeIngredient
        exclude = ('serving_size', 'created', 'updated',)

Pull your data through ajax into the my_custom_serving_size_field

Your view: -

def my_view(request):
    if request.method == 'POST':
        form = CustomRecipeIngredientForm(data=request.POST)
        if form.is_valid():
            new_recipe_ingredient = form.save(commit=False)
            new_recipe_ingredient.serving_size = ServingSize.objects.get(pk=form.cleaned_data['my_custom_serving_size_field'])
            new_recipe_ingredient.save()             

            return HttpResponseRedirect(reverse('redirect_to_wherever'))
    else:
        form = CustomRecipeIngredientForm()
    return render_to_response('path/to/my_template.html', {'form': form}, context_instance=RequestContext(request))

Of course, your ServingSize.objects.get() logic will depend on what your are pulling through ajax and how. Try something along these lines and let us know.

chefsmart
If I do this then how will I set the serving_size field? I am using this with inlineformset_factory. I am a little new to this, thanks.
iHeartDucks
Post your ServingSize model code and we will try it out.
chefsmart
Did it, thanks.
iHeartDucks
I've tried to post a raw guide on how to go about it. Check the edited answer.
chefsmart
I get an error which says [{'custom_serving_size': [u'Select a valid choice. 1 is not one of the available choices.']}]. The selectlist is empty and not tied to anything so why doesn't it accept any value I provide? This is my field custom_serving_size = forms.ChoiceField(required=False, widget=forms.Select(attrs={'class':'ddl'}))
iHeartDucks
That's because you need to supply choices for a ChoiceField. Use another type of field instead.
chefsmart
Yes, that's what I thought I had to do. I think I will create my own field. Thanks for your help.
iHeartDucks