How to update choices for forms.ChoiceField in Django? - python

I have field in forms.py:
main_choices = ((1,'option 1'),(2,'option 2'),(3,'option 3'))
sub_choices = ((1,'PlaceHolder'))
class MainForm(forms.Form):
type = forms.ChoiceField(choices=main_choices)
sub_type = forms.ChoiceField(choices=sub_choices)
HTML:
<form action="{% url 'app:get_files' %}" method="POST">
{% csrf_token %}
{{ form.type }}
{{ form.sub_type }}
<button type="submit" class="app">GET</button>
</form>
view.py
def get_files(request):
//Some action with complete form
return FileResponse(zip_file, as_attachment=True)
def get_ajax(request):
if request.is_ajax():
data = request.POST.copy()
if 'type' in data:
type = int(data['type'])
if type == 2:
sub_choices = getChoices(type)
elif type ==3:
sub_choices = getChoices(type)
return HttpResponse()
Currently, server catches ajax post data from the type field.
I don't know how to put sub_choices from get_ajax action to sub_type field in forms.
Can anyone explain how to do that?

Related

form.as_hidden doesn't pass values to POST

My form has initial values in it. I use form.as_hidden to hide the values and pass those values through a POST request. However, the hidden values are not passing through. Is there a way through this?
views.py
def car_detail_view(request, id):
if request.method == "POST":
form = CarForm(request.POST)
print(form.is_valid())
if form.is_valid():
car_save = form.instance
get_car = Car.objects.get(number_plate=car_save.number_plate)
get_car.available = False
get_car.save()
return redirect('/')
else:
print(form.errors)
else:
car = Car.objects.get(id=id)
form = CarForm(initial={'brand':car.brand, 'number_plate':car.number_plate, 'price':car.price,
'available':car.available})
args = {
'car':car,
'form':form
}
return render(request, 'map/confirmation.html', args)
confirmation.html
<h1>Confirmation of Booking</h1>
{% block content %}
<p>Brand: {{ car.brand }}</p>
<p>Number Plate: {{ car.number_plate }}</p>
<p>Price: {{ car.price }}</p>
<p> Are you sure you want to book? <p>
<form class="" method="post">
{% csrf_token %}
{{ form.as_hidden }}
<input type="submit" value="Book {{ car.brand }}">
</form>
{% endblock %}
Error
<ul class="errorlist"><li>brand<ul class="errorlist"><li>This field is required.</li></ul></li><li>number_plate<ul class="errorlist"><li>This field is required.</li></ul></li><li>price<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
Django doesn't have a form.as_hidden method. Therefore {{ form.as_hidden }} will render as the empty string '' in your template.
You can use the as_hidden method for individual form fields.
{{ form.number_plate.as_hidden }}
If you use values from hidden fields, you might need to add code to prevent the user altering the field values (e.g. with their browser's developer tools). However, in your case you don't need to get the values from the form, you can fetch them from the database.
def car_detail_view(request, id):
if request.method == "POST":
car = Car.objects.get(id=id)
car.available = False
car.save()
return redirect('/')
else:
car = Car.objects.get(id=id)
args = {
'car':car,
}
return render(request, 'map/confirmation.html', args)
Once you've got this working, you might want to think about what happens if two users try to book the same car at once.

Passing value and ID from Request.POST

I am trying to have a website with multiple input type ="text" fields which as a default have values from database in them.
Goal is to have X input types where X=number of entries in database and one extra input type box to add a new entry.
The problem is that if user edits a textfield and hits submit, Request.POST['event'] returns only the new value, not the id of the box that has been edited,
This is my current code:
<form method="post">
{% csrf_token %}
{% for choice in event %}
<form method ='POST'> {% csrf_token%}
<input type="text" name = "event" id="event{{ forloop.counter }}" value="{{choice.txt}}"><br>
<input type = 'submit' value = 'Zapisz'/>
</form>
{% endfor %}
<form method ='POST'> {% csrf_token%}
{{form.as_p}}<br>
<input type = 'submit' value = 'Zapisz'/>
</form>
and views.py:
def rpg_create(request):
try:
event = get_list_or_404(Event)
except:
event = ""
if request.method == 'POST':
try:
Adjusted_event = request.POST['event']
print (Adjusted_event)
except:
pass
form = RpgForm(request.POST or None)
if form.is_valid():
print(form)
form.save()
context = {
'form': form,
'event': event
}
return redirect('/rpgmaker', context)
else:
form = RpgForm()
context = {
'form': form,
'event': event
}
return render(request,"rpgmaker/rpg.html",context)

Didnt return HttpResponse object. It returned None instead - django

I am getting an error with a view that i have and i was wondering if anyone can help me figure out where it is coming from. I am pretty sure it is something small that I am not seeing where it is coming from...
Within the view there will be a form that is displayed for the user to input informaiton, once the form is submitted, it is processed and then redirect to the users home...
Here is the error:
ValueError at /transfer/
The view tab.views.transfers didn't return an HttpResponse object. It returned None instead.
Request Method: POST
Request URL: http://localhost:8000/transfer/
Django Version: 1.8.6
Exception Type: ValueError
Exception Value:
The view tab.views.transfers didn't return an HttpResponse object. It returned None instead.
Here is the views.py
def transfers(request):
if 'username' not in request.session:
return redirect('login')
else:
username = request.session['username']
currentUser = User.objects.get(username = username)
if request.method == 'POST':
form = TransferForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
from_acct = cd['from_acct']
to_acct = cd['to_acct']
amount = cd['amount']
memo = cd['memo']
new_transfer = Transfers.objects.create(
user = currentUser,
from_acct = from_acct,
to_acct = to_acct,
amount = amount,
memo = memo,
frequency = 1,
status = 1,
)
return redirect('home_page')
else:
form = TransferForm()
form.fields['from_acct'].queryset = Accounts.objects.filter(user = currentUser).all()
message = 'please fill out the below form'
parameters = {
'form':form,
'currentUser':currentUser,
'message':message,
}
return render(request, 'tabs/user_balance.html', parameters)
Here is the html file:
{% extends "base.html" %}
{% block content %}
<h1>Transfer Money</h1>
{% if message %}
<p>{{message}}</p>
{% endif %}
<form action="." method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" name="submit" value="submit">
</form>
{% endblock %}
Here is the forms.py file portion
class TransferForm(forms.ModelForm):
acct_choices = (('tabz', 'Tabz - Username'),
('Wells Fargo', 'Wells Fargo - Username'))
from_acct = forms.TypedChoiceField(
choices=acct_choices, widget=forms.RadioSelect, coerce=int
)
to_acct = forms.TypedChoiceField(
choices=acct_choices, widget=forms.RadioSelect, coerce=int
)
class Meta:
model = Transfers
fields = ['from_acct', 'to_acct', 'amount', 'memo']
labels = {
'from_acct':'from',
'to_acct':'to',
}
from django.http import HttpResponse, HttpResponseRedirect
if request.method == 'POST':
form = TransferForm(request.POST)
if form.is_valid():
...
return HttpResponseRedirect(reverse_lazy('home'))
else:
form.fields['from_acct'].queryset = Accounts.objects.filter(user = currentUser).all()
message = 'please fill out the below form'
parameters = {
'form':form,
'currentUser':currentUser,
'message':message,
}
return render(request, 'tabs/user_balance.html', parameters)
html add form.errors
{% extends "base.html" %}
{% block content %}
<h1>Transfer Money</h1>
{% if message %}
<p>{{message}}</p>
{% endif %}
<form action='your_url/' method="POST">
{% csrf_token %}
{{ field.errors }}
{{ form.as_p }}
<input type="submit" name="submit" value="submit">
</form>
{% endblock %}
Well, this error should be thrown simply because you are giving an invalid form to your view. If you look at the logic of the view, if it is a POST and form is not valid the view does not return anything... well None for python. That's the error you are getting right?
Try to put an else statement with return after return redirect('home_page') and see if this fixes this part.

Page not save forms data in django

I am trying to do exercise 7 in tango with django where i must save new page to specific category by adding information to forms.
So I write new code to forms.py
class PageForm(forms.ModelForm):
title = forms.CharField(max_length=128, help_text="Please enter the title of the page.")
url = forms.CharField(max_length=200, help_text="Please enter the url of the page.")
views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
class Meta:
model = Page
def clean(self):
cleaned_data = self.cleaned_data
url = cleaned_data.get('url')
if url and not url.startswith('http//'):
url = 'http://' + url
cleaned_data['url'] = url
return cleaned_data
fields = ('title', 'url', 'views')
def save_form(self):
if self.is_valid():
page = self.save(commit=False)
try:
cat = Category.objects.get(name=category_name)
page.category = cat
except:
return render_to_response('rango/add_category.html', {}, context)
page.views = 0
page.save()
return True
else:
return False
Then I edit views.py
def add_page(request, category_name_url):
context = RequestContext(request)
category_name = decode_url(category_name_url)
if request.method == 'POST':
form = PageForm(request.POST)
if form.save_form():
return category(request, category_name_url)
else:
print form.errors
else:
form = PageForm()
return render_to_response( 'rango/add_page.html',
{'category_name_url': category_name_url,
'category_name': category_name,
'form': form},
context)
def decode_url(element):
return element.replace(' ', '_')
def encode_url(element):
return element.replace('_', '')
Then I created template:
Rango
<body>
<h1>Add page to category</h1>
<form id="page_form" method="post" action="/">
{% csrf_token %}
{% for hidden in forms.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
{{ field.errors }}
{{ field.help_text }}
{{ field }}
{% endfor %}
<input type="submit" name="Submit" value="Add a page" />
</form>
</body> </html>
I have made reference to new page in category.html
Add page to this category
And of course a edit urls.py
> url(r'^rango/category/(?P<category_name_url>\w+)/add_page/$',
> views.add_page, name='add_page'),
Everything is visible and I am able to fill form. But when i confirm data by clicking on button, page is return to home and not in category and new page is not save in database. So please someone, where a have error?
Your <form> element has the action set to action="/". This makes the form submit send a POST request to the homepage not the current page. You can correct this by making the form action empty action="" to submit to the current URL or be explicit and use the {% url %} template tag for the required form action.

Flask WTForms - How to identify multiple submit buttons on the same form? [duplicate]

I have multiple form on the same page that send post request to same handler
in flask.
I am generating forms using wtforms.
what is the best way to identify which form is submitted ?
I am currently using action="?form=oneform". I think there should be some better method
to achieve the same?
The solution above have a validation bug, when one form cause a validation error, both forms display an error message. I change the order of if to solve this problem.
First, define your multiple SubmitField with different names, like this:
class Form1(Form):
name = StringField('name')
submit1 = SubmitField('submit')
class Form2(Form):
name = StringField('name')
submit2 = SubmitField('submit')
....
Then add a filter in view.py:
....
form1 = Form1()
form2 = Form2()
....
if form1.submit1.data and form1.validate(): # notice the order
....
if form2.submit2.data and form2.validate(): # notice the order
....
Now the problem was solved.
If you want to dive into it, then continue read.
Here is validate_on_submit():
def validate_on_submit(self):
"""
Checks if form has been submitted and if so runs validate. This is
a shortcut, equivalent to ``form.is_submitted() and form.validate()``
"""
return self.is_submitted() and self.validate()
And here is is_submitted():
def is_submitted():
"""Consider the form submitted if there is an active request and
the method is ``POST``, ``PUT``, ``PATCH``, or ``DELETE``.
"""
return _is_submitted() # bool(request) and request.method in SUBMIT_METHODS
When you call form.validate_on_submit(), it check if form is submitted by the HTTP method no matter which submit button was clicked. So the little trick above is just add a filter (to check if submit has data, i.e., form1.submit1.data).
Besides, we change the order of if, so when we click one submit, it only call validate() to this form, preventing the validation error for both form.
The story isn't over yet. Here is .data:
#property
def data(self):
return dict((name, f.data) for name, f in iteritems(self._fields))
It return a dict with field name(key) and field data(value), however, our two form submit button has same name submit(key)!
When we click the first submit button(in form1), the call from form1.submit1.data return a dict like this:
temp = {'submit': True}
There is no doubt when we call if form1.submit.data:, it return True.
When we click the second submit button(in form2), the call to .data in if form1.submit.data: add a key-value in dict first, then the call from if form2.submit.data: add another key-value, in the end, the dict will like this:
temp = {'submit': False, 'submit': True}
Now we call if form1.submit.data:, it return True, even if the submit button we clicked was in form2.
That's why we need to define this two SubmitField with different names. By the way, thanks for reading(to here)!
Update
There is another way to handle multiple forms on one page. You can use multiple views to handle forms. For example:
...
#app.route('/')
def index():
register_form = RegisterForm()
login_form = LoginForm()
return render_template('index.html', register_form=register_form, login_form=login_form)
#app.route('/register', methods=['POST'])
def register():
register_form = RegisterForm()
login_form = LoginForm()
if register_form.validate_on_submit():
... # handle the register form
# render the same template to pass the error message
# or pass `form.errors` with `flash()` or `session` then redirect to /
return render_template('index.html', register_form=register_form, login_form=login_form)
#app.route('/login', methods=['POST'])
def login():
register_form = RegisterForm()
login_form = LoginForm()
if login_form.validate_on_submit():
... # handle the login form
# render the same template to pass the error message
# or pass `form.errors` with `flash()` or `session` then redirect to /
return render_template('index.html', register_form=register_form, login_form=login_form)
In the template (index.html), you need to render both forms and set the action attribute to target view:
<h1>Register</h1>
<form action="{{ url_for('register') }}" method="post">
{{ register_form.username }}
{{ register_form.password }}
{{ register_form.email }}
</form>
<h1>Login</h1>
<form action="{{ url_for('login') }}" method="post">
{{ login_form.username }}
{{ login_form.password }}
</form>
I've been using a combination of two flask snippets. The first adds a prefix to a form and then you check for the prefix with validate_on_submit(). I use also Louis Roché's template to determine what buttons are pushed in a form.
To quote Dan Jacob:
Example:
form1 = FormA(prefix="form1")
form2 = FormB(prefix="form2")
form3 = FormC(prefix="form3")
Then, add a hidden field (or just check a submit field):
if form1.validate_on_submit() and form1.submit.data:
To quote Louis Roché's:
I have in my template :
<input type="submit" name="btn" value="Save">
<input type="submit" name="btn" value="Cancel">
And to figure out which button was passed server side I have in my views.py file:
if request.form['btn'] == 'Save':
something0
else:
something1
A simple way is to have different names for different submit fields. For an
example:
forms.py:
class Login(Form):
...
login = SubmitField('Login')
class Register(Form):
...
register = SubmitField('Register')
views.py:
#main.route('/')
def index():
login_form = Login()
register_form = Register()
if login_form.validate_on_submit() and login_form.login.data:
print "Login form is submitted"
elif register_form.validate_on_submit() and register_form.register.data:
print "Register form is submitted"
...
As the other answers, I also assign a unique name for each submit button, for each form on the page.
Then, the flask web action looks like below - note the formdata and obj parameters, which help to init / preserve the form fields accordingly:
#bp.route('/do-stuff', methods=['GET', 'POST'])
def do_stuff():
result = None
form_1 = None
form_2 = None
form_3 = None
if "submit_1" in request.form:
form_1 = Form1()
result = do_1(form_1)
elif "submit_2" in request.form:
form_2 = Form2()
result = do_2(form_2)
elif "submit_3" in request.form:
form_3 = Form3()
result = do_3(form_3)
if result is not None:
return result
# Pre-populate not submitted forms with default data.
# For the submitted form, leave the fields as they were.
if form_1 is None:
form_1 = Form1(formdata=None, obj=...)
if form_2 is None:
form_2 = Form2(formdata=None, obj=...)
if form_3 is None:
form_3 = Form3(formdata=None, obj=...)
return render_template("page.html", f1=form_1, f2=form_2, f3=form_3)
def do_1(form):
if form.validate_on_submit():
flash("Success 1")
return redirect(url_for(".do-stuff"))
def do_2(form):
if form.validate_on_submit():
flash("Success 2")
return redirect(url_for(".do-stuff"))
def do_3(form):
if form.validate_on_submit():
flash("Success 3")
return redirect(url_for(".do-stuff"))
I haven't used WTForms but should work regardless. This is a very quick and simple answer; all you need to do is use different values for the submit button. You can then just do a different def based on each.
In index.html:
<div>
<form action="{{ url_for('do_stuff')}}" method="POST">
<h1>Plus</h1>
<input type = "number" id = "add_num1" name = "add_num1" required><label>Number 1</label><br>
<input type = "number" id = "add_num2" name = "add_num2" required><label>Number 2</label><br>
<input type = "submit" value = "submit_add" name = "submit" ><br>
</form>
<p>Answer: {{ add }}</p>
</div>
<div>
<form action="{{ url_for('do_stuff')}}" method="POST">
<h1>Minus</h1>
<input type = "number" id = "min_num1" name = "min_num1" required><label>Number 1</label><br>
<input type = "number" id = "min_num2" name = "min_num2" required><label>Number 2</label><br>
<input type = "submit" value = "submit_min" name = "submit"><br>
</form>
<p>Answer: {{ minus }}</p>
</div>
in app.py:
#app.route('/',methods=["POST"])
def do_stuff():
if request.method == 'POST':
add = ""
minus = ""
if request.form['submit'] == 'submit_add':
num1 = request.form['add_num1']
num2 = request.form['add_num2']
add = int(num1) + int(num2)
if request.form['submit'] == 'submit_min':
num1 = request.form['min_num1']
num2 = request.form['min_num2']
minus = int(num1) - int(num2)
return render_template('index.html', add = add, minus = minus)
Well here is a simple trick
Assume you Have
Form1, Form2, and index
Form1 <form method="post" action="{{ url_for('index',formid=1) }}">
Form2 <form method="post" action="{{ url_for('index',formid=2) }}">
Now In index
#bp.route('/index', methods=['GET', 'POST'])
def index():
formid = request.args.get('formid', 1, type=int)
if formremote.validate_on_submit() and formid== 1:
return "Form One"
if form.validate_on_submit() and formid== 2:
return "Form Two"
I normally use a hidden tag that works as an identifier.
Here is an example:
class Form1(Form):
identifier = StringField()
name = StringField('name')
submit = SubmitField('submit')
class Form2(Form):
identifier = StringField()
name = StringField('name')
submit = SubmitField('submit')
Then you can add a filter in view.py:
....
form1 = Form1()
form2 = Form2()
....
if form1.identifier.data == 'FORM1' and form1.validate_on_submit():
....
if form2.identifier.data == 'FORM2' and form2.validate_on_submit():
....
and finally in the HTML:
<form method="POST">
{{ form1.indentifier(hidden=True, value='FORM1') }}
</form>
<form method="POST">
{{ form2.indentifier(hidden=True, value='FORM2') }}
</form>
If you do it like this in the if statement it will check what was the identifier and if its equal it will run the form stuff you have in your code.
Example: Multiple WTForm in single html page
app.py
"""
Purpose Create multiple form on single html page.
Here we are having tow forms first is Employee_Info and CompanyDetails
"""
from flask import Flask, render_template, request
from flask_wtf import FlaskForm
from wtforms import StringField, IntegerField, FloatField, validators
from wtforms.validators import InputRequired
app = Flask(__name__)
app.config['SECRET_KEY'] = 'Thisisasecret'
class EmployeeInfo(FlaskForm):
"""
EmployeeInfo class will have Name,Dept
"""
fullName = StringField('Full Name',[validators.InputRequired()])
dept = StringField('Department',[validators.InputRequired()])
class CompanyDetails(FlaskForm):
"""
CompanyDetails will have yearOfExp.
"""
yearsOfExp = IntegerField('Year of Experiece',[validators.InputRequired()])
#app.route('/', methods = ['GET','POST'] )
def index():
"""
View will render index.html page.
If form is validated then showData.html will load the employee or company data.
"""
companydetails = CompanyDetails()
employeeInfo = EmployeeInfo()
if companydetails.validate_on_submit():
return render_template('showData.html', form = companydetails)
if employeeInfo.validate_on_submit():
return render_template('showData.html', form1 = employeeInfo)
return render_template('index.html',form1 = employeeInfo, form = companydetails)
if __name__ == '__main__':
app.run(debug= True, port =8092)
templates/index.html
<html>
<head>
</head>
<body>
<h4> Company Details </h4>
<form method="POST" action="{{url_for('index')}}">
{{ form.csrf_token }}
{{ form.yearsOfExp.label }} {{ form.yearsOfExp }}
<input type="submit" value="Submit">
</form>
<hr>
<h4> Employee Form </h4>
<form method="POST" action="{{url_for('index')}}" >
{{ form1.csrf_token }}
{{ form1.fullName.label }} {{ form1.fullName }}
{{ form1.dept.label }} {{ form1.dept }}
<input type="submit" value="Submit">
</form>
</body>
</html>
showData.html
<html>
<head>
</head>
<body>
{% if form1 %}
<h2> Employee Details </h2>
{{ form1.fullName.data }}
{{ form1.dept.data }}
{% endif %}
{% if form %}
<h2> Company Details </h2>
{{ form.yearsOfExp.data }}
{% endif %}
</body>
</html>

Categories