Set default value for hidden ModelForm field Django - python

I want to pass an initial value for HiddenInput form field in Meta class of ModelForm object. If the field is not hidden, e.g. as:
class Meta:
model = SomeModel
fields = ['some_id', 'some_amount',]
and I pass initial values via kwargs to this form constructor, then initial values are set to these fields correctly.
But when I try to hide one field (but I still need it to be set up to initial value from kwargs), as e.g.:
class Meta:
model = SomeModel
widgets = {'ord_id': forms.HiddenInput(),}
fields = ['some_id', 'some_amount',]
Then 'ord_id' is not set up to initial value from kwargs and I get the following error when trying to submit such form:
(Hidden field ord_id) Select a valid choice. That choice is not one of the available choices
So is there any way to pass an initial value to the Hidden form field correctly?

You can set defaults value to form fields in two ways.
first method is by passing default values while on initializing the form in your view.py i.e
from forms import ExampleForm
INITIAL_DATA = {'ord_id': 'some_id'}
def my_view(request):
...
if request.method == 'GET':
form = ExampleForm(initial=INITIAL_DATA)
if request.method == 'POST':
form = ExampleForm(request.POST)
...
Second is by overriding the form __init__ method i.e
class ExampleForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
"""If no initial data, provide some defaults."""
initial = kwargs.get('initial', {})
initial['ord_id'] = 'ord_id'
kwargs['initial'] = initial
super(ExampleForm, self).__init__(*args, **kwargs)

If you've verified with the inspection tool that your select element really does have the correct option selected, the problem may be that your field is disabled somehow instead of just hidden. I've seen similar error messages from attempting to submit disabled fields. If that's not the case, I may have an alternative solution for designating your fields as hidden.
If you are using django templates you can use widget tweaks to modify form fields in the template, which allows you to do things like add classes and styles or change values. So you can pass the initial arguments to your form as you have already and hide them using template tags. Hope this works for you!
{% for field in form %}
{% if field == form.hidden_field_name %}
{% render_field field hidden='True' id='hidden-field' class='hidden-field-class' %}
{% endif %}
{% endfor %}

Related

How to get instance values for form in django?

I've overridden a detail view so I can render form elements with render_field. However, when rendered they do not show the saved values. I can't set the value in the template because I can't put {{}} within {% %} syntax. How can I access and display the previously saved model instance values? (these are sliders that I want to keep as sliders, and they also have a lot of data attributes that I want to keep consistent, so I can't just write the inputs manually in the template)
In views.py:
class MyDetailEditMixin(SingleObjectMixin):
"""
Hybrid mixin to edit a detail
"""
model = MyModel
form_class = forms.MyForm
raise_execption = True
def get_context_data(self, **kwargs):
"""
expose the form
"""
kwargs.setdefault('form', forms.MyForm)
return super(MyDetailEditMixin, self).get_context_data(**kwargs)
class MyDetailView(MyDetailEditMixin, DetailView):
"""
Shows the details
"""
I feel like I need to explicitly mention the instance somehow? I'm not sure. The inputs render correctly with all their specific data attributes, just no set values.
I tried many different things, but in the end I ditched the mixin and edited MyDetailView with a get_form method (and within that I could tell it to use the instance):
class MyDetailView(DetailView):
"""
Shows the details
"""
form_class = forms.MyForm
def get_form(self):
form = self.form_class(instance=self.object)
return form
def get_context_data(self, **kwargs):
context = super(MyDetailView, self).get_context_data(**kwargs)
context.update({
'form': self.form_class(instance=self.get_object()),
})
return context
The render_field fields have their values filled with the saved instance values and all the attributes they need are there.

How to use Django form fields multiple times in a GET or POST

Here is what I have, a simple Django form
class survey (forms.Form):
answer = forms.ChoiceField(
widget = RadioSelect(),
choices = answers_select
)
Now, on my HTML page, I got not just one question but many! Is it possible to use the above answer field for all the questions? For all the questions, its just the same choices I have to show!
Say I have 3 questions:
How is my restaurant
How is the food
How is the service
choices for the above answer field are 1. good, 2. bad 3. worst
So, I don't want to create 3 form fields for the 3 questions as its redundant
Step back and think it clearly through--you'll need 3 ChoiceField to track the answer for 3 separate questions and there's no way around it.
What would be redundant is to actually repeat the form field construction call, especially if you were dealing with, say, 20 questions. In this case, rather than statically constructing those fields, you can store the list of questions as a class invariant and create the form fields dynamically during the forms construction.
Here's something to give you a starting idea on how you might go about doing it:
class SurveyForm(forms.Form):
questions = _create_questions('How is my restaurant?',
'How is the Food?',
'How is the service?')
def __init__(self, *args, **kwargs):
# Create the form as usual
super(SurveyForm, self).__init__(*args, **kwargs)
# Add custom form fields dynamically
for question in questions:
self.fields[question[0]] = forms.ChoiceField(label=question[1],
widget=forms.RadioSelect(),
choices=answers_select)
#classmethod
def _create_questions(cls, *questions):
return [(str(index), question) for index, question in enumerate(questions)]
You're looking for formsets. You could do something like this:
from django.forms.formsets import formset_factory
SurveyFormSet = formset_factory(survey, extra=3, max_num=3)
Add it to your context:
def get_context_data(self, request, *args, **kwargs):
data = super(MyView, self).get_context_data(request, *args, **kwargs)
data['formset'] = SurveyFormSet()
return data
Then use it in the template:
<form method="post" action="">
{{ formset.management_form }}
<table>
{% for form in formset %}
{{ form }}
{% endfor %}
</table>
</form>
During a post, you'll want to pass request.POST and request.FILES into the formset constructor:
formset = SurveyFormSet(request.POST, request.FILES)
It's all described pretty thoroughly in that linked documentation.

django: request.POST key is empty if the choicefield value is not set

I am currently beginning web development using django. In my application, I want a form with a varied number of questions and their choices to be presented.
In models.py, a table is create to store the questions
class QuizItems(models.Model):
question = models.CharField(max_length=255)
choices = SeparatedValuesField(token="$")
answer = models.IntegerField()
In form.py, I overload the __init__ method in Form class so as to pass qchoose, a list of QuizItems instances to create the form fields.
def choiceItem(question):
return [(unicode(idx), q) for idx, q in enumerate(question.choices)]
class QuizForm(forms.Form):
def __init__(self, qchoose, *args, **kwargs):
super(QuizForm, self).__init__(*args, **kwargs)
for q in qchoose:
self.fields[str(q.id)] = forms.ChoiceField(required=True,
label=q.question, widget=forms.RadioSelect(),choices=choiceItem(q))
Then in view.py
if request.method == 'POST':
idlst = request.POST.keys()
else:
# qchoose is a list of quizitems
form = QuizForm(qchoose)
In quiz.html
{% for field in form %}
<li><b> {{ field.label }} </b></li>
<ul> {{ field }} </ul>
{% endfor %}
I want to get idlst, the list of question id, that I can get the correct answers from. It works fine when all the choicefields are filled. The problem is if there is any choicefield value is empty, I won't get its key. I think since the request.POST is a dictionary, it is supposed to return all the keys even if its value is empty.
Could anyone help me what is wrong with my code or anything missing? Thank you!
You're supposed to use the form on POST as well, then call is_valid() and access the form's cleaned_data dict.

Hidden Field Flow Using Django

I'm trying to receive a POST then generate a form with new fields and pass along the values I received in the previous POST as hidden variables. I've done a lot of searching in documentation and can't seem to find anything that connects the two sides of this flow. I'm using Django 1.4 w/ Python 2.7.
views.py
from django.shortcuts import render_to_response
from gateway_interface.forms import newForm
def requestNewForm(request):
if (request.method == "POST"):
form = newForm(request)
return render_to_response('myTemplate.html', {'form' : form})
forms.py
from django import forms
class newForm(forms.Form):
def __init__(self, request):
my_passed_variable = request.POST['pass_variable']
a_new_variable = forms.CharField(max_length = 25)
my_passed_variable = forms.CharField(widget = forms.HiddenInput())
myTemplate.html
<form action="/myNextDjangoView/" method="post">
<div class="fieldWrapper">
I need this value: {{ form.a_new_variable }} <br>
</div>
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
<input type="submit" value="Submit">
</form>
I must be doing something fundamentally wrong. If I use the for loop in the template none of the visible fields show on the page. Nothing I've tried has caused the hidden fields to populate.
Any suggestions? Perhaps I'm missing an import somewhere? Is there something I need to import in forms.py to allow for the use of HiddenInput()?
EDIT 1:
I've modified forms.py to look like this:
form django import forms
class newForm(forms.Form):
a_new_variable = forms.CharField(max_length = 25)
my_passed_variable = forms.CharField(widget = forms.HiddenInput())
def __init__(self, *args, **kwargs):
super(newForm, self).__init__(*args, **kwargs)
This has not changed my output. I still get the same form with no fields showing (hidden or visible). What I need to do is instantiate with an initialization dictionary. (I think?) Where the dictionary contains the name and values for all the hidden fields.
initial_dict = { 'my_passed_variable' : request.POST.get('pass_variable') }
form = newForm(initial = initial_dict)
EDIT 2:
Using the initialization dictionary was a step in the right direction! I am now able to see the visible fields in my form but the hidden fields are still not populating.
views.py
from django.shortcuts import render_to_response
from gateway_interface.forms import newForm
def requestNewForm(request):
if (request.method == "POST"):
initial_dict = { 'my_passed_variable' : request.POST.get('pass_variable') }
form = newForm(initial = initial_dict)
return render_to_response('myTemplate.html', {'form' : form})
EDIT 3:
I've got it working. Thanks to Jordan Reiter for pushing me in the right direction. It turns out the problem was almost entirely the caching of my browser after EDIT 1 above. I moved to Chrome's incognito mode and everything just worked.
There is a definite problem with this code:
from django import forms
class newForm(forms.Form):
def __init__(self, request):
my_passed_variable = request.POST['pass_variable']
a_new_variable = forms.CharField(max_length = 25)
my_passed_variable = forms.CharField(widget = forms.HiddenInput())
First, it's incredibly confusing for there to be two variables with identical names (although one of them is self.my_passed_variable available throughout the form and the other is just my_passed_variable available in __init__ only). I can't help but think you're trying to tie the two variables together somehow, but you're not. Worst/best case scenario (if you rewrote my_passed_variable = request.POST['pass_variable'] as self.my_passed_variable = request.POST['pass_variable']) you're overwriting the value for form field object with a string.
Second, I'm assuming you snipped out a bunch of code from the __init__ function. You're missing the super which actually makes this a form. As it stands, the form object is not going to be instantiated correctly.
If you're trying to do what I think you're trying to do, you want to rewrite it this way:
from django import forms
class newForm(forms.Form):
# first, I'm going to put the fields at the top, I think that's more standard
a_new_variable = forms.CharField(max_length = 25)
my_passed_variable = forms.CharField(widget = forms.HiddenInput())
def __init__(self, request, *args, **kwargs):
super(newForm, self).__init__(*args, **kwargs)
self.fields['my_passed_variable'].initial = request.POST.get('pass_variable') # don't assume the variable is present!

Django - Passing parameters to inline formset

I am using inlineformset_factory to create fields for a many to many relationship between Clients and Sessions, with an intermediary Attendance model.
I have the following in my views file:
AttendanceFormset = inlineformset_factory(
Session,
Attendance,
formset=BaseAttendanceFormSet,
exclude=('user'),
extra=1,
max_num=10,
)
session = Session(user=request.user)
formset = AttendanceFormset(request.POST, instance=session)
And, as I needed to override one of the form fields, I added the following to the formset base class:
class BaseAttendanceFormSet(BaseFormSet):
def add_fields(self, form, index):
super(BaseAttendanceFormSet, self).add_fields(form, index)
form.fields['client'] = forms.ModelChoiceField(
queryset=Client.objects.filter(user=2))
Now, the form works correctly, but I need to pass a value into the formset so that I can filter the clients displayed based the current user rather than just using the id 2.
Can anyone help?
Any advice appreciated.
Thanks.
EDIT
For anyone reading, this is what worked for me:
def get_field_qs(field, **kwargs):
if field.name == 'client':
return forms.ModelChoiceField(queryset=Client.objects.filter(user=request.user))
return field.formfield(**kwargs)
How about utilizing the inlineformset_factory's formfield_callback param instead of providing a formset ? Provide a callable which in turns returns the field which should be used in the form.
Form fields callback gets as 1st parameter the field, and **kwargs for optional params (e.g: widget).
For example (using request.user for the filter, replace with another if needed:
def my_view(request):
#some setup code here
def get_field_qs(field, **kwargs):
formfield = field.formfield(**kwargs)
if field.name == 'client':
formfield.queryset = formfield.queryset.filter(user=request.user)
return formfield
AttendanceFormset = inlineformset_factory(
...
formfield_callback=get_field_qs
...
)
formset = AttendanceFormset(request.POST, instance=session)
To better understand it, see the usage of formfield_callback in Django's FormSet code.

Categories