Form does not validate. csrf_token included - python-3.x

I have following issue with validate_on_submit() method in my Flask application.
Quick overview what I have:
My form class is created dynamically based on input:
class EditUsers(FlaskForm):
submit = SubmitField('Submit')
def form_builder(roles_list):
class EditUsersForm(EditUsers):
pass
for role in roles_list:
if isinstance(role, tuple) and len(role) == 5:
if not role[2] and role[3]:
setattr(EditUsersForm, f'{role[0]}_{role[4]}_bool', BooleanField(label=role[0]))
setattr(EditUsersForm, f'{role[0]}_{role[4]}_date', SelectField('Expiration Period', choices=choices))
else:
raise IncorrectType
IncorrectType is custom Exception i prepared and choices are created using datetime in same file (This is irrelevant so I am not including it in code).
My route in flask app (simplified):
#### EDIT: I pasted the wrong route, POST and GET Methods are included###
#edit_users.route('/users', methods=['GET', 'POST'])
def users():
... # Some code there
form = form_builder(roles_to_form)
print(form.is_submitted())
print(form.validate())
print(form.validate_on_submit())
return render_template('edit_user.html',
data_dict=data_dict, # in data_dict i pass form fields names and some other data
form=form,
)
My template:
<!-- Some usual stuff goes there css js etc -->
<div >
<form class="form form-horizontal" method="post" role="form" style="margin: auto; text-align: center; width: 40%;">
{{ form.csrf_token() }}
<table class="table" align="center">
<thead>
<th>Role</th>
<th>Expiration Date</th>
<th>Give Role?</th>
</thead>
{% for field in data_dict['id_list'] %}
<tr>
<td align="left">{{ field[2] }}</td>
<td align="left">
{{ form[field[1]] }}
</td>
<td align="left">{{ form[field[0]] }}</td>
</tr>
{% endfor %}
<tr>
<td colspan="3" align="center">{{ form.submit() }}</td>
</tr>
</table>
</form>
</div>
What is my issue?
When I am hitting my Submit button, is_submitted() returns True but validate() does not, thus I cannot use typical if form.validated_on_submit() as it returns False even when I submit my form.
I dig a little and spot something unusual. I used protected members of form attributes, to check whatever validate() function sees as input:
for name in form._fields:
print(name)
inline = getattr(form.__class__, 'validate_%s' % name, None)
print(inline)
The output (don't mind names of fields):
submit
None
Engineer_2_bool
None
Engineer_2_date
None
Operator_3_bool
None
Operator_3_date
None
Supervisor_4_bool
None
Supervisor_4_date
None
Guest_5_bool
None
Guest_5_date
None
csrf_token
None
I don't know why my form does not have validate_{name} attributes.

I made a working example from your code, and I ended up with the problem you described.
If I reversed well your code, it seems that form[field[1]] is your BooleanField or SelectField. So to render it in a template your have to use form[field[1]]() (can use render_field as well).
So :
<tr>
<td align="left">{{ field[2] }}</td>
<td align="left">
{{ form[field[1]] }}
</td>
<td align="left">{{ form[field[0]] }}</td>
</tr>
corrected into :
<tr>
<td align="left">{{ field[2] }}</td>
<td align="left">
{{ form[field[1]]() }}
</td>
<td align="left">{{ form[field[0]]() }}</td>
</tr>
https://flask.palletsprojects.com/en/1.1.x/patterns/wtforms/#forms-in-templates
As you are using a FlaskForm, in your template you have to replace {{ form.csrf_token() }} by {{ form.csrf_token }}
https://flask-wtf.readthedocs.io/en/stable/csrf.html#html-forms
[EDIT Does not make any difference]
[Edited after w8eight's comment]
The route is not authorized for POST (and the form makes a POST request as seen in <form class="form form-horizontal" method="post" [...].
So you have to change : #edit_users.route('/users', methods=['GET']) to #edit_users.route('/users', methods=['GET','POST'])

The problem was with type of data passed to choices of SelectField. I passed list of tuples with datetime.datetime to it. When changed type to str everything works smoothly.

Related

Laravel 9 Livewire Pagination is not working at all

In my project(s) I want to make use of Livewire Pagination. I have setup everything according to the Livewire Docs. I make use of components to view everything.
I tried the same as you can find in the following code in my real projects, but nothing works.
Here is my code of a test setup (and also here nothing works):
Model User
<?php
namespace App\Models;
use App\Casts\UserRoleCast;
use App\Constants\UserRole;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Jetstream\HasProfilePhoto;
use Laravel\Sanctum\HasApiTokens;
use Livewire\WithPagination;
class User extends Authenticatable
{
use HasApiTokens;
use HasFactory;
use HasProfilePhoto;
use Notifiable;
use TwoFactorAuthenticatable;
use WithPagination;
/**
* The attributes that are mass assignable.
*
* #var string[]
*/
protected $fillable = [ ....etc.....
UserPagination.php
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use App\Models\User;
use Livewire\WithPagination;
class UserPagination extends Component
{
use WithPagination;
public function render()
{
return view('livewire.user-pagination', [
'users' => User::paginate(5)
])->layout('layouts.guest');
}
}
Blade view
<div>
<table class="table min-w-full mb-4">
<thead>
<tr class="border-b-2 border-gray-300">
<th class="px-6 py-3 text-left text-sm leading-4 tracking-wider">ID</th>
<th class="px-6 py-3 text-left text-sm leading-4 tracking-wider">Naam</th>
<th class="px-6 py-3 text-left text-sm leading-4 tracking-wider">Email</th>
<th class="px-6 py-3 text-left text-sm leading-4 tracking-wider">Password</th>
</tr>
</thead>
<tbody>
#forelse($users as $user)
{{-- <tr class="border-b border-gray-500" wire:key="user-{{ $user->id }}"> --}}
<tr class="border-b border-gray-500">
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5">
{{ $user->id }}
</td>
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5">
{{ $user->name }}
</td>
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5">
{{ $user->email }}
</td>
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5">
{{ $user->password }}
</td>
</tr>
#empty
<tr>
<td colspan="6" class="px-6 py-4 whitespace-no-wrap text-sm leading-5">Geen sponsors gevonden</td>
</tr>
#endforelse
</tbody>
</table>
{{ $users->links() }}
</div>
composer.json
"laravel/framework": "^9.19",
"laravel/jetstream": "^2.13",
"laravel/sanctum": "^3.0",
"laravel/tinker": "^2.7",
"livewire/livewire": "^2.5",
Furthermore
I have my #livewireStyles and my #livewireScripts at the right place. I know it's right, because the rest of the application is working.
But clicking on the links doesn't do anything. Nothing changes in de URI and nothing happens on screen.
What is wrong here? Why doesn't it working?
I tried everything according to the Livewire Docs and 'solutions' I found online.
SOLVED
I made a mistake by adding a use statement in the models, the use statement:
use WithPaginator
This is a Livewire trait and only for livewire components.
I removed the use statement and everything worked.
Another problem is when I load for example all Users with pagination in the mount method of a component I get an error. Solution here was to load all Users in de render method.

Django print all permissions of a users in template

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

flask wtforms triggering a python function with post

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>

database base values in WTForms without submitting

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

Trying to use laravel pagination breaks my controller/view

I'm trying to get Pagination working in Laravel. I've not used pagination before so am trying to use some examples from the docs and google results. I'm wondering if I need to turn 'pagination' on somewhere in config.
Here's my simple working controller:
public function get_index() {
$locations = Location::all();
return View::make('location.index')->with('locations', $locations)->render();
}
When I try and add pagination like this it breaks:
public function get_index() {
$locations = Location::paginate(5);
return View::make('location.index')->with('locations', $locations)->render();
}
..and I get the error:
Unhandled Exception
Message:
Error rendering view: [location.index]
Trying to get property of non-object
Here's my location.index view:
#layout('layouts.blank')
#section('content')
<div class="row">
<div class="twelve columns">
<div role="main" id="content">
<h3>Locations - All</h3>
#if($locations)
<table class="twelve">
<thead>
<tr>
<th style="text-align: left;">Address</th>
<th>Area</th>
<th>Region</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
#foreach($locations as $location)
<tbody>
<tr>
<td style="text-align: left;">{{ $location->company,', ',$location->add_name,', ',$location->add_city }}</td>
<td> – </td>
<td> – </td>
<td>{{ HTML::link('location/update/'.$location->id, '',array('class'=>"foundicon-edit updateicon")) }}</td>
<td>{{ HTML::link('location/delete/'.$location->id, '',array('class'=>"foundicon-remove warnicon")) }}</td>
</tr>
</tbody>
#endforeach
</table>
#else
Looks like we haven't added any locations, yet!
#endif
<p>{{ HTML::link('location/create', 'Create a location', array('class'=>"small radius button")) }}</p>
</div>
</div>
</div>
#endsection
I hadn't read deeply enough into the subject. It's now working and here's what I had to change in the view:
//from:
#foreach($locations as $location)
//to:
#foreach($locations->results as $location)
That returned just 5 results. Then to add links to the footer of my table I added this HTML/Blade:
<tfoot>
<tr>
<td colspan="5"> {{ $locations->links() }} </td>
</tr>
</tfoot>
Hope someone else benefits as I didn't find this terribly clear in the docs.

Resources