Reputation: 13
I am trying to make a drop down select form (category) in django.
The form renders well on the webpage but when I try to submit I get the error Select a valid choice. That choice is not one of the available choices.
I have done everything possible within my capability to resolve this. if you have any idea on how to go about this please help.
model.py
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('detail', args=[str(self.id)])
# return reverse('home')
class Post(models.Model):
title = models.CharField(max_length=100)
text = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
edited = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
category = models.CharField(max_length=100, default='coding')
def __str__(self):
return f'{self.title} by {self.author} {self.pk}'
def get_absolute_url(self):
return reverse('detail', args=[str(self.id)])
# return reverse('home')
form.py
from django import forms
from .models import Post, Category
choices = Category.objects.all().values_list('name','name')
choices_list = []
for item in choices:
choices_list.append(item)
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('title', 'category', 'author','text')
widgets={
'title': forms.TextInput(attrs={'class':'form-control'}),
'category': forms.Select(choices=choices_list, attrs={'class':'form-control'}),
'author': forms.TextInput(attrs={'class':'form-control', 'id':'author'}),
# 'author': forms.Select(attrs={'class':'form-control'}),
'text': forms.Textarea(attrs={'class':'form-control','placeholder':choices_list}),
}
class EditForm(forms.ModelForm):
class Meta:
model = Post
fields = ('title', 'text')
widgets={
'title': forms.TextInput(attrs={'class':'form-control'}),
'text': forms.Textarea(attrs={'class':'form-control','placeholder':"less than 500 words"}),
# 'author': forms.Select(attrs={'class':'form-control'})
}
views.py
class createarticleview(CreateView):
template_name='posts/addpost.html'
model = Post
form_class = PostForm
#fields = '__all__'
# fields = ('title','text') for certain fields
def get_context_data(self, *args, **kwargs):
cat_menu = Category.objects.all()
context = super(createarticleview, self).get_context_data(*args, **kwargs)
context['cat_menu'] = cat_menu
return context
addpost.html
{%extends 'index.html'%}
{%block content%}
{% if user.is_authenticated %}
<div class="container">
<h3>add post...!!!.{{user.username}}</h3>
<br>
<div class="mb-3">
<form method="POST"> {% csrf_token%}
{{form.as_p}}
<button type="submit" class="btn btn-info"> post</button>
</form>
</div>
</div>
<script>
var name = "{{user.username}}";
if(document.getElementById("author").value=name)
document.getElementById('author').readOnly = true;
</script>
{% else%}
<h3>you are not logged in</h3>
{%endif%}
{%endblock content%}
Upvotes: 0
Views: 5939
Reputation: 8837
Firstly, Always use PascalCase
while defining the name of class
, like you can give CreateArticleView
rather than createarticleview
.
you haven't given choices
while defining your model that is Post
and given models.CharField()
.
Update your Post
model with choices
attribute.
Try this:
models.py
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
CATEOGRY_TYPES = (
('sp', 'sport'),
('te', 'technology'),
('bu', 'business')
)
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('detail', args=[str(self.id)])
# return reverse('home')
class Post(models.Model):
title = models.CharField(max_length=100)
text = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
edited = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
category = models.CharField(
choices=CATEOGRY_TYPES, max_length=2, default='coding')
def __str__(self):
return f'{self.title} by {self.author} {self.pk}'
def get_absolute_url(self):
return reverse('detail', args=[str(self.id)])
# return reverse('home')
views.py
from django.shortcuts import render
from .models import Post, Category
from .forms import PostForm
from django.views.generic.edit import CreateView
class CreateArticleView(CreateView):
template_name = 'posts/addpost.html'
model = Post
form_class = PostForm
success_url = '/success/'
def success(req):
return render(req, 'posts/success.html')
Rest of things will be remain same.
You can do it without reverse
method by direclty making ForeignKey
field in your Post
model.
you can also do this:
models.py
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=100)
text = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
edited = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
category = models.ForeignKey(
Category, on_delete=models.CASCADE, default='coding')
def __str__(self):
return f'{self.title} by {self.author} {self.pk}'
views.py
from django.shortcuts import render
from .models import Post, Category
from .forms import PostForm
from django.views.generic.edit import CreateView
class CreateArticleView(CreateView):
template_name = 'posts/addpost.html'
model = Post
form_class = PostForm
success_url = '/success/'
def success(req):
return render(req, 'posts/success.html')
Your forms.py
can be remain same.
Remember: choices
while defining models will be given more preference than ForeignKey
.
Upvotes: 1