I made a Flask WTForm to allow my user to confirm a series of informations. I show the form pre-filled with the informations, and the user can modify it and submit the form. However, even when no error occurs (form.errors is empty), form.validate() always returns False. What am I doing wrong?
App
#app.route('/validation', methods=['GET', 'POST'])
def validation():
# initiate form
item = session.get('item', None)
form = AttrForm(request.form)
# pre-fill validation
form.price.data = item['price']
form.surface.data = item['surface']
form.rooms.data = item['rooms']
form.year.data = item['year']
# get area options and pre-fill
options = get_options()
form.subarea.choices = options
form.subarea.data = get_choice(options, item['subarea'])
# catch errors
if not form.validate_on_submit():
display = {'url': False, 'fill' : True, 'valid' : False}
return render_template('index.html', display=display, form=form)
# set new values
item['price'] = request.form['price']
item['surface'] = request.form['surface']
item['rooms'] = request.form['rooms']
item['year'] = request.form['year']
item['subarea'] = request.form['subarea']
session['item'] = item
return redirect(url_for('results'))
HTML
{% block attr_form %}
<h2>Attribute Form</h2>
<form action="/validation" method="POST">
<table>
<tr>
<td>Loyer (hors charges)</td>
<td>{{ render_field(form.price) }}</td>
</tr>
<tr>
<td>Surface</td>
<td>{{ render_field(form.surface) }}</td>
</tr>
<tr>
<td>Année de construction</td>
<td>{{ render_field(form.year) }}</td>
</tr>
<tr>
<td>Nombre de pièces</td>
<td>{{ render_field(form.rooms) }}</td>
</tr>
<tr>
<td>Quartier administratif</td>
<td>{{ render_field(form.subarea) }}</td>
</tr>
</table>
<input type=submit value="Je valide"></p>
</form>
{% endblock %}
Helpers
{% macro render_field(field) %}
<dd>{{ field }}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<ul>{{ error }}</ul>
{% endfor %}
</ul>
{% endif %}
</dd>
{% endmacro %}
Form
class AttrForm(FlaskForm):
price = DecimalField('price', validators=[DataRequired()])
subarea = SelectField('subarea', coerce=int)
surface = DecimalField('surface', validators=[DataRequired()])
year = IntegerField('year', validators=[DataRequired()])
rooms = IntegerField('rooms', validators=[DataRequired()])
First make sure your defined a SECRET_KEYin your flask config. You need to do this in order for CSRFprotection to work. http://flask-wtf.readthedocs.io/en/stable/csrf.html
Second, add the csrf token to your html form by inserting form.hidden_tag.
<form action="/validation" method="POST">
{{ form.hidden_tag() }}
<table>
<tr>
...
See http://flask-wtf.readthedocs.io/en/stable/quickstart.html for details.
Related
I am editing the user permissions in templates. And I want to display checked checkbox if user has permissions or unchecked if user has not specific permissions.
My View.py codes are as below.
def EditUserView(request,id=0):
user = User.objects.get(pk=id)
permission = Permission.objects.all()
return render(request,'edituser.html',{"userdata":user,"permissions":permission})
And My templates code are as given below.
<div class="table-wrapper">
<table class="table">
<thead>
<tr>
<th>Permissions</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{% for perm in permissions%}
<tr>
<td id="perm">{{perm}}</td>
<td><input type="checkbox" name="status" id="status" onclick="ChangeUserPermissions(this,userid='{{userdata.id}}',permission='{{perm}}')"></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
My objectives of the code is only display checked checkbox if have permissions or unchecked if not have permissions
So you need to register custome tag for this it can be filter:
#register.filter
def has_perm(user, perm):
return user.has_perm(perm)
then in template:
{% for perm in permissions%}
<tr>
<td>{{perm}}</td>
<td><input type="checkbox" name="status" onclick="ChangeUserPermissions(this,userid='{{userdata.id}}',permission='{{perm}}')"
{% if user|has_perm:perm %} selected {% endif %}>
</td>
</tr>
{% endfor %}
those ids on td tags wont be uniqe
I don't want to use javascript as its probably just a one-off usecase. Here's my code and the problem statement follows.
# Form class
class ManageContainers(FlaskForm):
stop_container = SubmitField('stop')
# HTML Render
{% for i in containers %}
<tbody>
<tr>
<th scope="row">{{ i.short_id }}</th>
<td>{{ i.name }}</td>
<td>{{ i.image.tags }}</td>
<td>{{ i.ports }}</td>
<td>
<form action="#" method="post">
{{ form.stop_container() }}
</form>
</td>
</tr>
</tbody>
{% endfor %}
# Actual app route
#app.route('/list-containers', methods=['POST','GET'])
def index():
containers_list = client.containers.list(all=False)
form = ManageContainers()
if form.is_submitted():
print("stop the container")
delete_container(HOW_TO_GET_THIS?)
return redirect(url_for('index'))
return render_template('index.html', containers=containers_list, form=form)
def delete_container(container_id):
container = client.containers.get(container_id)
container.stop()
container.remove()
I am using docker sdk for python and basically trying to stop / start containers. I am stuck where I want to use that button that says "stop" which will delete the container.
Important - It is actually calling a function like this because I can see "stop the container" in my console. But I don't know how to pass the ID (i.id) of the container while the function is getting called.
Here's a screenshot of what the page actually looks like to save you sometime.
SCREENSHOT
Since you are not taking any user input for any fields, I don't think, it's related to WTForms.
You can try the below steps:
Create a route for stopping the container:
#app.route('/stop-container/<id>', methods=['POST'])
def stop_container(id):
delete_container(id)
return redirect(url_for('index'))
Change your form to:
<form action={{ url_for('stop_container', id=i.short_id) }} method='post'>
{{ form.stop_container() }}
</form>
On my ListView page, I need to be able to loop through a list of statuses that come from my views.py.
I can do it on the DetailView, but I am struggling with the same process on the ListView.
I have searched and searched and can not seem to find help with my specific problem.
Working code for DetailView:
managers.py
class ICCRequestManager:
...
#property
def statuses(self):
""" Current status of ICC request """
if not self.is_submitted:
yield "Created, not yet submitted"
if self.is_submitted and not self.legal_signoff_status:
yield "Waiting for security review"
if self.is_submitted and not self.security_signoff_status:
yield "Waiting for legal review"
if self.legal_signoff_status and self.security_signoff_status:
yield "Fully reviewed, ICC team is working"
views.py
from . import managers
...
class ICCRequestMixin:
""" Mixin for the request model """
model = models.ICCRequest
context_object_name = 'icc_request'
class ICCRequestDetailView(LoginRequiredMixin, ICCRequestMixin, DetailView):
""" View to see the current status of an ICC request """
template_name = "icc/request_status.html"
def get_context_data(self, **kwargs):
""" Add required context """
context = super().get_context_data(**kwargs)
context["icc_request_manager"] = managers.ICCRequestManager(self.object)
return context
request_status.html
<ul>
{% for value in icc_request_manager.statuses %}
<li>{{ value }}</li>
{% endfor %}
</ul>
The above displays a simple bulleted list as expected.
Problem code:
views.py
class ICCRequestListView(LoginRequiredMixin, ICCRequestMixin, ListView):
""" View to list requests """
template_name = "icc/request_list.html"
paginate_by = 10
def get_context_data(self, **kwargs):
""" Add required context """
context = super().get_context_data(**kwargs)
context["icc_request_manager"] = managers.ICCRequestManager(self.object_list)
return context
Working portion:
request_list.html
<table class="table table-striped table-bordered">
<tr>
<th scope="col">ICC #</th>
<th scope="col">Company</th>
<th scope="col">Brief Description</th>
<th scope="col">LOB</th>
<th scope="col">Requester</th>
<th scope="col">Status</th>
</tr>
{% for request in icc_request %}
<tr>
<th scope="row">{{ request.id }}</th>
<td>{{ request.company_name}}</td>
<td>{{ request.summary }}</td>
<td>{{ request.owner_area }}</td>
<td>{{ request.requested_on_behalf_of }}</td>
<!--- I want the statuses list here --->
</tr>
</table>
Attempt to loop through like on the detail page:
...
<!--- I want the statuses list here --->
<td>
<ul>
{% for status in request.icc_request_manager.statuses %}
<li>
{{ status }}
</li>
{% endfor %}
</ul>
</td>
{% endfor %}
</tr>
</table>
This does not give an error, but it does not display anything (while the request_status.html page does).
Only error is the following linting error on the get_context_data:
"Parameters differ from overridden 'get_context_data' method."
So I figured it out.
1) get_context_data on the ListView has nothing to do with it. Not needed.
2) I needed to change from yields to returning a list:
def statuses(self):
""" Current status of icc request """
statuses = list()
if not self.is_submitted:
statuses.append("Created, not yet submitted")
if self.is_submitted and not self.legal_signoff_status:
statuses.append("Waiting for security sign off")
if self.is_submitted and not self.security_signoff_status:
statuses.append("Waiting for security review")
if self.legal_signoff_status and self.security_signoff_status:
statuses.append("Fully reviewed, ICC team is working")
return statuses
3) Added a method to the model:
#property
def get_icc_request_manager(self):
""" Get the manager for this one request """
# Needed to import managers inside the method to prevent Circular import problem
import icc.managers
mgr = icc.managers.ICCRequestManager(icc_request=self)
return mgr
4) Used with:
<table class="table table-striped table-bordered">
<tr>
<th scope="col">ICC #</th>
<th scope="col">Company</th>
<th scope="col">Brief Description</th>
<th scope="col">LOB</th>
<th scope="col">Requester</th>
<th scope="col">Status</th>
</tr>
{% for request in icc_request %}
{% with request_manager=request.get_icc_request_manager %}
<tr>
<th scope="row">{{ request.id }}</th>
<td>{{ request.company_name}}</td>
<td>{{ request.summary }}</td>
<td>{{ request.owner_area }}</td>
<td>
{% if request.requested_on_behalf_of %}
{{ request.requested_on_behalf_of }}
{% elif request.requested_by %}
{{ request.requested_by }}
{% else %}
{% endif %}
</td>
<td>
<ul>
{% for status in request_manager.statuses %}
<li>
{{ status }} test
</li>
{% endfor %}
</ul>
</td>
{% endwith %}
{% endfor %}
</tr>
</table>
Above is an image of what I am attempting to build: A form that is at the top while the area to display a result list is below. When I hit 'Go!', the part below does not render the list as I hoped. Also, I am not sure if this is the 'proper' way to go about doing this.
The Class Based View that i use:
class EntryListView(ListView):
template_name = 'finance/entry_list.html'
now = datetime.now()
year = now.year
context_object_name = 'entry_list'
model = Entry
paginate_by = 10
month_list = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October',
'November', 'December']
year_list = list(range(Entry.objects.earliest('input_date').input_date.year,
Entry.objects.latest('input_date').input_date.year))
def get_context_data(self, **kwargs):
context = super(EntryListView, self).get_context_data(**kwargs)
# https://stackoverflow.com/questions/18232851/django-passing-variables-to-templates-from-class-based-views
context.update({
'month_list': self.month_list,
'year_list': self.year_list,
})
return context
# This method ensures that I can customize the list of entries returned.
def get_queryset(self):
# https://stackoverflow.com/questions/22902457/django-listview-customising-queryset
if self.request.method == 'GET':
print('I have entered here!')
month = self.request.GET.get('month')
year = self.request.GET.get('year')
print('month: ' + str(month))
print('year: ' + str(year))
if month or year is None:
return Entry.objects.filter(input_date__month=datetime.now().month,
input_date__year=datetime.now().year).order_by('-input_date').all()
else:
return Entry.objects.filter(input_date__month=month,
input_date__year=year).order_by('-input_date').all()
Here is my urls.py:
url(r'entry/$', login_required(views.EntryListView.as_view()), name='list_entries'),
The EntryListView is also in charged of ensuring that the form is populated with the right 'Dropdown values'.
And here is the template:
{% extends 'base.html' %}
{% block body_content %}
<div class="wrapper">
{% include 'finance/finance_sidebar.html' %} <!-- Add this for inheritance -->
<div class="container">
<div class="row">
<form class="well contact-form" method='GET'>
<label>Month:</label>
<select class="well form-control" name="month">
{% for month in month_list %}
<option value="{{ forloop.counter }}">{{ month }}</option>
{% endfor %}
</select>
<label>Year:</label>
<select class="well form-control" name="year">
{% for year in year_list %}
<option value="{{ year }}">{{ year }}</option>
{% endfor %}
</select>
<button type="submit" class="btn btn-default">Go!</button>
</form>
</div>
<div class="row">
{% if entry_list %}
<div class="container">
<table class="table table-hover">
<thead>
<tr>
<th>No.</th>
<th width="100">Input Date</th>
<th>Category</th>
<th>Tag</th>
<th>Description</th>
<th>Value</th>
<th>Transfer Type</th>
<th>Remarks</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{% for entry in entry_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ entry.input_date|date:'d M Y' }}</td>
<td>{{ entry.category }}</td>
<td>{{ entry.tag }}</td>
<td>{{ entry.description }}</td>
<td>${{ entry.value }}</td>
<td>{{ entry.transfer_type }}</td>
<td>{{ entry.remarks }}</td>
<td>
<form class="flex-container" method="post" action="{% url 'finance:update_entry' pk=entry.id %}" >
{% csrf_token %}
<div class="input-group">
<input type="hidden" name="id" value="{{ entry.id }}">
<button name="update" type="submit" class="btn btn-warning">EDIT </button>
</div>
</form>
</td>
<td>
<form class="flex-container" method="post" action="{% url 'finance:delete_entry' %}" >
{% csrf_token %}
<div class="input-group">
<input type="hidden" name="id" value="{{ entry.id }}">
<button name="delete" type="submit" class="btn btn-danger">DELETE </button>
</div>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="col-sm-7 col-sm-offset-5">
{% if is_paginated %}
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
previous
{% endif %}
<span class="page-current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_page }}.
</span>
{% if page_obj.has_next %}
next
{% endif %}
</span>
</div>
{% endif %}
</div>
{% else %}
<p>Please make sure you have specified a month and the year.</p>
{% endif %}
</div>
</div>
</div>
{% endblock %}
I am again, not sure if this is the right way to approach it. I have seen something called Mixins, but I have no clue how to use them. I did a little print statements while debugging and i found that the data from the forms indeed are able to be accessed inside the get_queryset() method. I also made sure that my DB had such a record and i even typed it in my python shell to be sure that the query is not faulty.
Your if-else statement in your view is wrong. if month or year is None: will always evaluate to true since it can be rewritten as if (month) or (year is None) and you are actually posting month value to your view.
Instead, you could rewrite it as: if month is None or year is None:.
I am trying to develop a WTForm where users can select one or many part numbers in a table. After the user enters a part number I want to show the master data associated to it (right next to the part number). Such as weight, price etc., rendered in the same template. An SQLIte Table is holding the master data for all part numbers.
At the end, the intention is to sum up the values (price, weight) in a seperate line for the part numbers entered in the WTForm list.
All I find in documentation for WTForm processing is related to "on_submit". But users will never submit the form.
I believe I do not have the right implementation approach right now. First, my current coding is not updating the values in the form, second I dont want to have a submit button in order to see the content_values.
class kundenanalyse_items(FlaskForm):
ka_fm = SelectField('Futtermittel', choices=[('a', 'a Wert'), ('b', 'b
Wert'), ('17', 'irgendwas')])
ka_fm_menge = IntegerField('g/Tag (Tagesplan) bzw. g/Woche (Wochenplan)')
ka_fm_content01 = IntegerField('ka_fm_content01')
ka_fm_content02 = DecimalField('ka_fm_content02')
#app.route('/kundenanalyse', methods=['GET', 'POST'])
def kundenanalyse():
ka_line01 = kundenanalyse_items()
if request.method == 'POST':
flash('Daten an DB gesendet {} : {} + {} :
{}'.format(ka_line01.ka_fm.data, ka_line01.ka_fm_menge.data,
ka_line02.ka_fm.data))
ka_line01.ka_fm_content01.data = '100' * ka_line01.ka_fm_menge.data
ka_line01.ka_fm_content02.data = '200' * ka_line01.ka_fm_menge.data
return redirect(url_for('kundenanalyse'))
return render_template('kundenanalyse.html', ka_line01=ka_line01)
kundenanlyse.html:
{% extends 'layout.html' %}
{% block body %}
{% for message in get_flashed_messages() %}
<div class=flash style="color: orangered;">
{{ message }}
</div>
{% endfor %}
<form method="POST", action="/kundenanalyse")>
<div class="tg-wrap"><table class="tg" style="undefined;">
<tr>
<th class="tg-wh92">{{ ka_line01.ka_fm.label }}</th>
<th class="tg-wh92">{{ ka_line01.ka_fm_menge.label }}</th>
<th class="tg-wh92">{{ ka_line01.ka_fm_content01.label }}</th>
<th class="tg-wh92">{{ ka_line01.ka_fm_content02.label }}</th>
</tr>
<tr>
<td class="tg-e3ma">{{ ka_line01.ka_fm }}</td>
<td class="tg-sh4c">{{ ka_line01.ka_fm_menge }}</td>
<td class="tg-hkz2">{{ ka_line01.ka_fm_content01 }}</td>
<td class="tg-hkz2">{{ ka_line01.ka_fm_content02 }}</td>
</tr>
</table>
</div>
<input type="submit" value="Submit">
</form>
{% endblock %}
thank you in advance.
Michael