Reputation: 1365
I use the form Bannerform
to create new Banner
object trough the add_banner
views (and template). I use the class Options
to definite which affiliation
objects to permit in the form Bannerform
(affiliation
field).
I'm trying to pass choices from the views to the form but it give me ValueError: too many values to unpack (expected 2)
My code worked when new_affiliation
was a ForeignKey but now I need more values. I think I must definite 'choices' in the views
or I will have problem on the first migration (it appear to call the database tables from the models.py
but not from the views.py
, so if I put Options.objects.get(id=1)
on the models.py
it give error because the tables don't exist yet).
My form.py
:
from django import forms
from core.models import Options, Banner, Affiliation #somethings other
class BannerForm(forms.ModelForm):
name = forms.CharField(max_length=32)
affiliation = forms.ChoiceField('choices')
#affiliation = forms.ModelChoiceField('choices') #same error
class Meta:
model = Banner
exclude = (#some fields)
My models.py
:
from django.db import models
from django.contrib.auth.models import User
from django import forms
class Options(models.Model):
new_affiliation = models.ManyToManyField('Affiliation')
#new_affiliation = models.ForeignKey('Affiliation') #this worked (with some changes in views)
class Affiliation(models.Model):
name = models.CharField(max_length=32, unique=True)
class Banner(models.Model):
name = models.CharField(max_length=32, unique=True)
affiliation = models.ForeignKey(Affiliation)
My views.py
:
def add_banner(request):
if request.method == 'POST':
#some code here
else:
options = Options.objects.get(id=1)
print(options.new_affiliation.all()) #controll
choices = options.new_affiliation.all()
print(choices) #controll
form = BannerForm(choices, initial={
#some code regarding other fields
})
return render(request, 'core/add_banner.html', {'form': form})
My add_banner.html
:
<form role="form" id="banner_form" enctype="multipart/form-data "method="post" action="../add_banner/">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
{{ field.errors }}
{{ field.label }}
{{ field }}
{{ field.help_text }}
<br />
{% endfor %}
Any help will be apreciated.
Updated. I changed only views.py
:
def add_banner(request):
if request.method == 'POST':
#some code here
else:
options = Options.objects.get(id=1)
print(options.new_affiliation.all()) #controll
choices = tuple(options.new_affiliation.all())
print(choices) #controll
form = BannerForm(choices, initial={
#some code regarding other fields
})
return render(request, 'core/add_banner.html', {'form': form})
But still give error.
Update 2. If I pass choices directly from form.py it works:
My views.py
:
def add_banner(request):
if request.method == 'POST':
#some code here
else:
form = BannerForm(request.POST or None, initial={
#some code regarding other fields
})
return render(request, 'core/add_banner.html', {'form': form})
My forms.py
:
class BannerForm(forms.ModelForm):
options = Options.objects.get(id=1)
choices = options.new_affiliation.all()
name = forms.CharField(max_length=32)
affiliation = forms.ModelChoiceField(choices)
Unluckly this give problems on the first migration (see above).
I'm trying to pass choices using some init method...
My forms.py
:
class BannerForm(forms.ModelForm):
name = forms.CharField(max_length=32)
affiliation = forms.ModelChoiceField(choices)
def __init__(self, *args, **kwargs):
options = Options.objects.get(id=1)
choices = options.new_affiliation.all()
#choices = kwargs.pop('choices')
super(RegentForm, self).__init__(*args, **kwargs)
self.fields['affiliation'] = choices
but it say that choices is not definite
Upvotes: 4
Views: 4237
Reputation: 1365
Done!
My form.py
:
class BannerForm(forms.ModelForm):
name = forms.CharField(max_length=32, label='Nome')
def __init__(self, *args, **kwargs):
options = Options.objects.get(id=1)
choices = options.new_affiliation.all()
super(BannerForm, self).__init__(*args, **kwargs)
self.fields['affiliation'] = forms.ModelChoiceField(choices)
self.fields['affiliation'].initial = choices
class Meta:
model = Banner
My views.py
:
def add_banner(request):
if request.method == 'POST':
#some code here
else:
form = BannerForm(request.POST or None, initial={
#some code here
})
return render(request, 'core/add_banner.html', {'form': form})
Thank you
Upvotes: 2
Reputation: 3015
From what I can see here, it looks like you are getting an error "too many values to unpack" because you are not sending "choices" as the correct type. A ChoiceField takes choices only as a tuple, as seen in the documentation for models. If you are looking to define choices based on a QuerySet, you'll have to convert it into a tuple which can be interpreted as valid "choices". In one of my projects for example, I needed to prepare a set of years as a tuple so that I could allow users to select from a list of pre-determined years. I specified the following function to do this:
def years():
response = []
now = datetime.utcnow()
for i in range(1900, now.year + 1):
response.append([i, str(i)])
return tuple(response)
Since tuples are meant to be immutable, it usually isn't a good idea to cast them, just based on principle. However, in this case it seems necessary as a measure to declare that you are okay with the possible variability with these statements.
In your specific situation, you might consider doing something like this:
choices = tuple(options.new_affiliation.all().values())
I have not tested this code, and I frankly am not completely familiar with your project and may be mistaken in some part of this response. As a result, it may require further tweaking, but give it a try. Based on your error, this is definitely where the program is breaking currently. Update here if you make any progress.
Upvotes: 2