How to retrieve ChoiceField value from a form?

I want to get the selected choice from a ChoiceField in a view:

views.py

def myFormSubmitView(request):
...
        if form.is_valid():
            print("valid form")
            blog_post = Blog_Post()
            blog_post.title = form.cleaned_data["title"]
            blog_post.body = form.cleaned_data["body"]

            **blog_post.categories = form.cleaned_data["categories"]** [[[PROBLEM HERE]]]]

            blog_post.save()
            return HttpResponseRedirect(request.path_info)

models.py

class Category(models.Model):
    name = models.CharField(max_length=30)
    #fix plural
    class Meta:
        verbose_name_plural = "categories"
    def __str__(self):
        return self.name

class Blog_Post(models.Model):
    title = models.CharField(max_length=255)
    author = models.ForeignKey(MyUser,on_delete=models.CASCADE)
    image = models.ImageField(null=True,upload_to='static/blog')
    body = models.TextField()
    created_on = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    categories = models.ManyToManyField("Blog_Post", related_name="posts")
    def __str__(self):
        return self.title

forms.py

from django.db import models
from django import forms

#model form
from blog.models import Blog_Post
from django.forms import ModelForm

class NewBlogForm(ModelForm):
    title = models.CharField(max_length=150)
    # sections ids
    section_ids =(
        (0, "section1"),
        (1, "section2"),
        (2, "section3"))
    categories = forms.ChoiceField(choices=section_ids)
    body = models.CharField(max_length=255)
    image = models.ImageField(upload_to='static/blog/images/', error_messages = {'invalid':("Image files only")},)
    class Meta:
        model = Blog_Post 
        fields = ['title','categories','body','image']
    def __str__(self):
        return self.title
...

When I try to get the value of the chosen category from the form, and empty string is returned.

Supposedly it should return the chosen “section_id” value but it doesn’t.

What am I doing wrong ?

Welcome @mabaashar !

I’m confused by a couple of things in your post.

First

Your model is named Blog_Post, however the form you are showing has:

Which is not the same model.

Also, in Blog_Post, you have:

But in your form you have:

With Blog_Post.categories being a ManyToManyField, the form field should be a ModelMultipleChoiceField. (But since your model form is referencing a different model, I’m not sure if this is a mismatch or not.)

Thank you for the reply,

I edited the original code; I changed the code before copying it here that’s why.

This still isn’t right, is it? Are other instances of Blog_Post what you’re looking to relate here?

I am trying to link the “choice” to “categories” in the “section_ids” variable. But my selection results to empty.

But what does this have to do with a ManyToManyField in the model?

To do this (select the choice in the section_ids) values, then the model field would be a CharField, not a relationship.

It results in a dropdown with the blog “categories” to choose from, everything works but the selection is an empty string in views.

Correct, because you have a mismatch between the type of field and the data being used.

1 Like

revising code, thank you tons for answering

it is unneccesary set fields attrs because you use modelform.
just set fields.

and you add setion_ids attr, but it is not in model attr.
so, even if you add setion_ids model won’t be use that value.

from blog.models import Blog_Post
from django.forms import ModelForm

class NewBlogForm(ModelForm):
    #title = models.CharField(max_length=150)
    # sections ids
    #section_ids =(
        #(0, "section1"),
        #(1, "section2"),
        #(2, "section3"))
    #categories = forms.ChoiceField(choices=section_ids)
    #body = models.CharField(max_length=255)
    #image = models.ImageField(upload_to='static/blog/images/', error_messages = {'invalid':("Image files only")},)
    class Meta:
        model = Blog_Post 
        fields = ['title','categories','body','image']
    def __str__(self):
        return self.title
...

if you want custom choice, set widgets.

from django.forms import models
class NewBlogForm(ModelForm):
    ...
    class Meta:
        widgets = {
            'categories': models.ModelChoiceField(queryset={category queryset})
        }
        ...

1 Like

٠I have changed the type of “categories” in “models.py” to categories = models.ForeignKey(Category,on_delete=models.CASCADE

ForeignKey is more suitable as you hinted to the wrong type @KenWhitesell

But it throws me a new ValueError now:

Cannot assign “‘1’”: “Post.categories” must be a “Category” instance.

The value 1 is chosen from the “section_ids” fed to the ChoiceField variable in forms.py

If Blog_Post.categories is a ForeignKey, the form field should be a ModelChoiceField.

I don’t understand why you’re trying to set this to a defined constant when the values need to exist in the referenced model.

1 Like

Now it worked probably ! thank you so much : )

For anybody reading the answer is not “Foreignkey” but “modelchoicefield” representing the Category model.

Thank you for your answer; I will also add the widget attribute to the modelForm right now.