I have three forms in three tabs respectively in a template.
I fill in the first tab, submit, fill in the second form, submit, fill in the third form, submit.
Is there a way to keep the data in each form after saving? I need to show them all together.
No, when I save the second form I lose my data on the first form.
input.html: template
<form class="tab-pane fade in active" id="demographics" method="post" >
<input type="hidden" name="form_id" value="demographics">
{%crispy frm%}
</form>
<form class="tab-pane fade" id="diagnosis" method="post">
<input type="hidden" name="form_id" value="diagnosis">
{%crispy frm_d%}
</form>
<form class="tab-pane fade" id="a_b_sickle" method="post">
<input type="hidden" name="form_id" value="a_b_sickle">
{%crispy frm_a_b_s%}
</form>
views.py
def input(request):
context = RequestContext(request)
if request.method == 'POST':
submitted = request.POST.get('form_id', '')
print submitted
if submitted == 'demographics':
# Get the Form1 instance
my_demographics = DemographicForm(request.POST)
#my_diagnosis = DiagnosisForm()
if my_demographics.is_valid():
my_demographics_object= my_demographics.save()
my_diagnosis=DiagnosisForm({'patient': my_demographics_object.patient_id, 'diagnosis_option': 'b-thalassaemia syndromes'})
my_a_b_sickle=A_b_sickle_thalForm({'patient': my_demographics_object.patient_id})
else:
my_diagnosis=DiagnosisForm()
my_a_b_sickle = A_b_sickle_thalForm()
elif submitted == 'diagnosis':
my_diagnosis = DiagnosisForm(request.POST)
my_demographics = DemographicForm()
my_a_b_sickle = A_b_sickle_thalForm()
if my_diagnosis.is_valid():
my_diagnosis_object=my_diagnosis.save()
my_a_b_sickle =A_b_sickle_thalForm({'patient': my_diagnosis_object.patient})
else:
my_demographics = DemographicForm()
my_a_b_sickle = A_b_sickle_thalForm()
elif submitted == 'a_b_sickle':
my_a_b_sickle = A_b_sickle_thalForm(request.POST)
my_demographics = DemographicForm()
my_diagnosis = DiagnosisForm()
if my_a_b_sickle.is_valid():
my_a_b_sickle.save()
else:
raise ValueError('No form specified !')
else:
my_demographics = DemographicForm()
my_diagnosis = DiagnosisForm()
my_a_b_sickle= A_b_sickle_thalForm()
return render(request,'input.html', {'frm':my_demographics, 'frm_d': my_diagnosis, 'frm_a_b_s': my_a_b_sickle})
Any ideas please?
You can either submit them using ajax or send them back filled in your context. If you can get the saved objects between request by any association they have you can try:
For the second way you can try something like this:
my_demographics = DemographicForm(my_demographic_object)
my_diagnosis = DiagnosisForm(my_diagnosis_object)
my_a_b_sickle= A_b_sickle_thalForm(my_a_b_sickle)
return render(request,'input.html', {'frm':my_demographics, 'frm_d': my_diagnosis, 'frm_a_b_s': my_a_b_sickle})
In fact, with that you can even make that work as an update form with a little extra using the 'instance' attribute of ModelForm.
Related
I am creating a multi-choice quiz app, I have created a view which shows the question and 4 option. I have given radio button to each option but is giving me this error:
MultiValueDictKeyError at /quiz/2/11/ 'choice'
views.py
def question_detail(request,question_id,quiz_id):
q = Quiz.objects.get(pk=quiz_id)
que = Question.objects.get(pk=question_id)
ans = que.answer_set.all()
selected_choice = que.answer_set.get(pk=request.POST['choice'])
if selected_choice is True:
come = que.rank
came = come + 1
later_question = q.question_set.get(rank=came)
return render(request,'app/question_detail.html',{'que':que , 'later_question':later_question, 'ans':ans})
else:
come = que.rank
later_question = q.question_set.get(rank=come)
return render(request, 'app/question_detail.html', {'que': que, 'later_question': later_question, 'ans': ans})
question_detail.html
<form action="{% 'app:detail' quiz_id=quiz.id question_id=que.id %}" method="post">
{% csrf_token %}
{% for choice in que.answer_set.all %}
<input type="radio" name="choice" id="choice{{forloop.counter}}" value="{{choice.id}}">
<label for="choice{{forloop.counter}}">{{choice.answer}}</label>
{% endfor %}
</form>
Okay like I said in my comment, you're most likely getting that error because the POST object will be empty during a normal GET request. So you should wrap everything that's meant to happen after a request in an IF block:
if request.method === 'POST':
selected_choice = que.answer_set.get(pk=request.POST['choice'])
# Every other post-submit task
You should always check for the POST method in your views if you're expecting form data. Others have answered this more in-depth before so I would just direct you there:
What does request.method == "POST" mean in Django?
I'm trying to implement a form that is used to update information that has previously been posted by a user. Unfortunately, I am getting a TypeError: 'str' object is not callable.
I was looking for solutions online but could not find any - my guess is that the error has something to do with the fact that I am trying to prefill the value of a Select Field but I might be wrong.
views.py
#users.route('/<int:query_id>/update', methods=['GET', 'POST'])
#login_required
def update_query(query_id):
query = Model.query.get_or_404(query_id)
if query.author != current_user:
abort(403)
form = QueryForm()
if form.validate_on_submit():
query.property_type = form.property_type.data
query.property_type_details = form.property_type_details.data
db.session.commit()
return redirect(url_for('users.user_profile', username=current_user.username))
elif request.method == 'GET':
form.property_type = query.property_type
form.property_type_details = query.property_type_details
return render_template('users/update-query.html', form=form)
forms.py
class QueryForm(FlaskForm):
submit = SubmitField('Send')
property_type = SelectField(u'Type', choices=[('House', 'House'), ('Apartment', 'Apartment')])
property_type_details = SelectField(u'Detail', choices=[('Something', 'Something'),('SomethingElse', 'SomethingElse')])
template
<form method='POST' class="query-form" action="" enctype="multipart/form-data">
{{form.hidden_tag()}}
<h4 class="text-center">Info</h4>
<div class="form-row">
<div class="form-group col-md-4">
{{form.property_type.label}}
{{form.property_type(class="form-control")}}
</div>
<div class="form-group col-md-4">
{{form.property_type_details.label}}
{{form.property_type_details(class="form-control")}}
</div>
</div>
</form>
Most recent call and error
File "/Users/1/Desktop/Code/Project/Name/main/templates/users/update-query.html", line 33, in block "content"
{{form.property_type_details(class="form-control")}}
TypeError: 'str' object is not callable
Pre-filling both form fields means setting the data attribute for both field instances. 1
Currently, instances of both fields are overridden by values retrieved from the database.
The block pre-filling both fields when updated as below addresses errors with rendering both fields pre-filled in the template.
elif request.method == 'GET':
form.property_type.data = query.property_type
form.property_type_details.data = query.property_type_details
I added a newsletter sign-up form to the footer area of my site and such had to use an inclusion_tag because I couldn't bind it to a view. It works well and as expected, but I have a strange thing happening that I apparently am not smart enough to figure out myself :)
After the form is submitted, I receive the email confirmation, but two things happen:
The Django Success Message doesn't appear until after I manually refresh the page.
Where my form sits, there are syntax 'Missing Variable' errors. I included a screenshot for reference and my form code is below. The form fields re-appear and errors go away after refreshing the page again.
home_tags.py
#register.inclusion_tag('pages/tags/footer_newsletter_signup.html', takes_context=True)
def footer_newsletter_signup(context):
request = context['request']
title = 'Newsletter Signup'
form = MailingListForm(request.POST or None)
if form.is_valid():
mailing_list_full_name = form.cleaned_data.get('mailing_list_full_name')
mailing_list_phone = form.cleaned_data.get('mailing_list_phone')
mailing_list_email = form.cleaned_data.get('mailing_list_email')
mailing_list_subject = 'Submission from Newsletter Signup'
mailing_list_message = 'Yes, please add me to marketing emails.'
from_email = settings.DEFAULT_FROM_EMAIL
recipient_list = [from_email, 'charles#studiorooster.com']
ctx = {
'mailing_list_subject': mailing_list_subject,
'mailing_list_full_name': mailing_list_full_name,
'mailing_list_email': mailing_list_email,
'mailing_list_phone': mailing_list_phone,
'mailing_list_message': mailing_list_message
}
message = get_template('pages/newsletter_signup_email.html').render(Context(ctx))
msg = EmailMessage(mailing_list_subject, message, to=recipient_list, from_email=from_email)
msg.content_subtype = 'html'
msg.send()
messages.success(request, "Thank you, you've been added to our list.")
return HttpResponse('/')
context = {
'form': form,
'title': title,
}
return context
footer_newsletter_signup.html
<form action='' method='POST' role='form' class="form-inline">
{% csrf_token %}
<div class="form-group">
{{ form.mailing_list_full_name }}
</div>
<div class="form-group">
{{ form.mailing_list_phone }}
</div>
<div class="form-group">
{{ form.mailing_list_email }}
</div>
<button class="button button-lg button-square button-pasific hover-ripple-out" type='submit'>Subscribe</button>
</form>
Then I just add the tag to my template like:
{% footer_newsletter_signup %}
Answering this
Ok, so here is where I am confused. I have a dozen views and this form is a Call-to-Action form that sits at the top of the footer. How do I bind this form to every view without repeating the code everywhere? Thank you for your help.
You need to create separate view to handle this form and provide action param in form tag pointing to this view.
Here is general idea, code my not work
#template
<form action='{% url "send-mail" %}' method='POST' role='form' class="form-inline">
...
#views
def send_mail(request):
form = MailingListForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
mailing_list_full_name = form.cleaned_data.get('mailing_list_full_name')
mailing_list_phone = form.cleaned_data.get('mailing_list_phone')
mailing_list_email = form.cleaned_data.get('mailing_list_email')
mailing_list_subject = 'Submission from Newsletter Signup'
mailing_list_message = 'Yes, please add me to marketing emails.'
from_email = settings.DEFAULT_FROM_EMAIL
recipient_list = [from_email, 'charles#studiorooster.com']
ctx = {
'mailing_list_subject': mailing_list_subject,
'mailing_list_full_name': mailing_list_full_name,
'mailing_list_email': mailing_list_email,
'mailing_list_phone': mailing_list_phone,
'mailing_list_message': mailing_list_message
}
message = get_template('pages/newsletter_signup_email.html').render(Context(ctx))
msg = EmailMessage(mailing_list_subject, message, to=recipient_list, from_email=from_email)
msg.content_subtype = 'html'
msg.send()
messages.success(request, "Thank you, you've been added to our list.")
return HttpResponse('/')
#tags
#register.inclusion_tag('pages/tags/footer_newsletter_signup.html', takes_context=True)
def footer_newsletter_signup(context):
title = 'Newsletter Signup'
form = MailingListForm()
context = {
'form': form,
'title': title,
}
return context
#url
url('r^send-mail/$', send_mail, name='send-email')
New to Django and having problem seeing form fields displayed. What I see is just the submit button. If pressed, the form is finally presented, but with the format for a form that had bad data (typical 'this field is required' error for each box, red box, etc).
The form works fine after entering data and again pressing submit (stores entries in my db). I have a number of forms on the same page that have the same behavior.
Example of one form:
#model
class dbPara(models.Model): #parameters
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
username = models.CharField(max_length=10)
turns = models.FloatField(default=27)
units = models.FloatField(default=5)
rise = models.FloatField(default=2.9)
rescutL = models.FloatField(default=0.0833333333)
rescutH = models.FloatField(default=0.333333333)
LorR = models.CharField(max_length=1, default='R')
def __str__(self):
return self.timestamp, self.username, self.turns, self.units, self.rise, self.rescutL, self.rescutH, self.LorR
#form
class ParaForm(ModelForm):
class Meta:
model = dbPara
widgets = {'username': forms.HiddenInput()}
fields =['username', 'turns', 'units', 'rise', 'rescutL', 'rescutH', 'LorR']
#view
def importParameters(request):
if request.method == 'GET':
form = ParaForm()
else:
form = ParaForm(request.POST)
if form.is_valid():
entry=dbPara(username = request.POST.get('username'),
turns = request.POST.get('turns'),
units = request.POST.get('units'),
rise = request.POST.get('rise'),
rescutL = request.POST.get('rescutL'),
rescutH = request.POST.get('rescutH'),
LorR = request.POST.get('LorR')
)
entry.save()
return render(request, 'main.html',
{'ParaHTML' : form })
#url
urlpatterns = patterns('Inputs.views',
url(r'^importParameters/$', 'importParameters', name='urlParameters'),
)
#main.html
<div class='col-lg-3'>
<h4>Set Rosetta Parameters</h4>
<action="{% url "urlParameters" %}" method="post">{% csrf_token %}
{{ ParaHTML|crispy }}
<input type="hidden" name = "username" value = "{{ user.get_username }}">
<input type="submit" class="btn btn-primary" value="Set">
</form>
</div>
Appreciate any advice (better simple than 'most correct but complicated')
Could it be due to using default in the model? Would that not 'fill in the form' and result in 'POST' at the initial visit to the page, resulting in just the button? Thoughts?
One Suggesestion here ....
if Using request.POST.get('anything') simply then it Will raise error if particular string not find as in example('anything') string...
Because request.POST.get('anything') will return None if 'anything' is not in request.POST.
Additionally, .get allows you to provide an additional parameter of a default value which is returned if the key is not in the dictionary.
e.g: Corrected will be request.POST.get('anything', 'mydefaultvalue')
After i submit my form using GET method and then refresh the page the data get resubmitted
i am using javascript for form validation
my views are:
def show(request,post_id):
try:
p = post.objects.get(pk=post_id)
c = comment.objects.filter(blog_id=p)
if 'cbox' in request.GET:
c = comment(text=request.GET['cbox'],name=request.GET['cname'],blog=p)
c.save()
c_list = comment.objects.filter(blog_id=p)
except post.DoesNotExist:
raise Http404
return render_to_response('show.html',{'post':p,'c_list':c_list})
my form is:
<form name="comment" action="" method="get" onsubmit="return validateForm()">
<input id="carea" type="text" placeholder="leave a comment" name="cbox" >
<input id="cb" type="submit" value="Post" />
<input id="cn" type="text" placeholder="Name" name="cname">
</form>
i want that when i refresh my page my data should not get resubmited
thanks
If you really insist on using GET to submit which practically is not a good method. You should do a request redirect using HttpResponseRedirect from the server side which will remove the query string from the url . This way it wouldn't resumit the form.
def show(request,post_id):
try:
p = post.objects.get(pk=post_id)
c = comment.objects.filter(blog_id=p)
if 'cbox' in request.GET:
c = comment(text=request.GET['cbox'],name=request.GET['cname'],blog=p)
c.save()
#Do a redirect here
return HttpResponseRedirect("URL of the page you would like to redirect")
c_list = comment.objects.filter(blog_id=p)
except post.DoesNotExist:
raise Http404
return render_to_response('show.html',{'post':p,'c_list':c_list})