Flask-WTForms .validate_on_submit() never executes - flask-wtforms

So basically I want to have a Updateform() form that allows users to update their account details. All my other forms (register, etc.) work perfectly fine but this specific form never validates on submit. Hence when I press the submit button the page just refreshes but the .validate_on_submit() code doesn't execute.
I've looked through the forums and a common issue I found is the .CSRF token missing, but I'm using form.hidden_tag() which I read should work perfectly fine. So it seems that my issue is unique.
I've been looking on the forums for hours but haven't found a solution.
Here is my form code:
class Updateform(FlaskForm):
email = StringField('Email:', validators=[DataRequired(), Email()])
picture = FileField('Update Profile Picture:', validators=[FileAllowed(['jpg', 'png'])])
submit = SubmitField("Update")
def validate_email(self, email):
if email.data != User.email:
if User.query.filter_by(email=email.data).first():
raise ValidationError('Email has already been registered')
Here is the route:
#users.route('/account', methods=['GET', 'POST'])
#login_required
def account():
form = Updateform()
print("hello")
if form.validate_on_submit():
print(form)
print("YES!!!")
name = current_user.name
pic = add_profile_pic(form.picture.data, name)
current_user.profile_image = pic
current_user.email = form.email.data
db.session.commit()
flash("Account Updated")
# elif request.method == "GET":
# form.email = current_user.email
profile_image = url_for('static', filename='profile_pics/'+current_user.profile_image)
return render_template('account.html', profile_image=profile_image, form=form)
And here is the html code:
{% extends "base.html" %}
{% block content %}
<div align="center">
Hi {{ current_user.name }}<br>
<img align="center" src="{{ url_for('static', filename='profile_pics/'+current_user.profile_image) }}">
</div>
<div class="container">
<form method="post">
{{ form.hidden_tag() }}
<div class="form-group">
{{ form.email.label(class='form-group') }}
{{ form.email(class='form-control') }}
</div>
<div class="form-group">
{{ form.picture.label(class='form-group') }}
{{ form.picture(class='form-control') }}
</div>
<div class="form-group">
{{ form.submit() }}
</div>
</form>
</div>
{% endblock %}
The extra classes you see are from the bootstrap library incase anyone is wondering.

Hello you could find out what the problem is by adding a else for you if form.validate_on_submit(): and have it do this
for error in form.email.errors:
print(error)
for error in form.picture.errors:
print(error)
this should tell you what is not working hope this helps and I have not tested this so it could have typos

Related

Omines Datatables with Turbo and Stimulus

I am trying to use Turbo in a new Symfony development. I'm following Turbo: Drive, Frames & Streams as a reference! and previously Symfony UX: Stimulus. Both topics are new to me and as if that weren't enough, I don't have much experience with Javascript.
All good except that I have not been able to get Omines Datatables to work under this scheme. I understand that I must create a Stimulus component but I have not achieved even the most basic thing, which is to load the Datatable.
I wonder if someone can guide me or if they have gone through the same thing, maybe they can provide a practical example of how to do it. Is it too much to ask?
In general, I usually load the Datatables in the following way:
{% block body %}
...
<div class="row">
<div class="col-12">
<div id="app_provinciaList">
<div class="d-flex justify-content-center">
<div class="spinner-border m-5" role="status">
<span class="sr-only">Cargando...</span>
</div>
</div>
</div>
</div>
</div>
...
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script>
$(function () {
var grillaApp_provincias = $('#app_provinciaList').initDataTables( {{ datatable_settings(datatable) }}, {
searching: true,
}).then(function (dt) {
dt.on('init', function(settings, json) {
$('#dt_filter input').attr("placeholder", "Provincia...");
$('#dt_filter input').width(300);
});
});
});
</script>
{% endblock %}

How can i style my django filter with bootstrap or CSS

i'm new to django here and still learning. So, i created a filter using django-filter and i didn't know how to style it (bootstrap or CSS) because i really don't like the default styling. Can anyone help me with it? i already googled it but didn't find anything useful.
filters.py
`
class CompLink_Filter(django_filters.FilterSet):
start_date = DateFilter(field_name="date_added", label='Date ajout' ,lookup_expr='gte')
company_name = CharFilter(field_name='company_name', label='Nom Entreprise' ,lookup_expr='icontains')
sector = CharFilter(field_name='sector',label='Secteur' , lookup_expr='icontains')
size = CharFilter(field_name='size', label='Taille' ,lookup_expr='icontains')
phone = CharFilter(field_name='phone', label='Téléphone' ,lookup_expr='icontains')
employees_on_linkedin = CharFilter(field_name='employees_on_linkedin', label='Employés sur Linkedin :' ,lookup_expr='icontains')
type = CharFilter(field_name='type', label='Type' ,lookup_expr='icontains')
founded_in = CharFilter(field_name='founded_in', label='Fondée En' ,lookup_expr='icontains')
specializations = CharFilter(field_name='specializations', label='Spécialisations' ,lookup_expr='icontains')
class Meta:
model = Comapny_Profile
fields= '__all__'
exclude= ['company_link','website','head_office','address']`
displaying the filter in my template:
<form class="" action="" method="get">
{% for field in myFilter.form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
<button class="btn btn-primary" type="submit" name="button">Recherche</button>
</form>
You could use jQuery or javascript to manipulate the DOM. When the tags are created you can style it. For example.
$("input").addClass("form-group");

Cannot write data to db in Flask

I am working on a small reading tracking app in Flask. I cannot seem to write data from one of my routes, below:
#app.route('/add_book', methods=['GET', 'POST'])
#login_required
def add_book():
form=BookForm()
if request.method=='POST':
if form.validate_on_submit():
book=Book(
title=form.title.data,
author=form.author.data,
# category=form.category.data,
# added_on=form.added_on.data,
# done=form.done.data,
user_id=current_user
)
db.session.add(book)
db.session.commit()
flash('Book added')
return redirect(url_for('books'))
else:
flash('ERROR. The book not added.')
return render_template('add_book.html', form=form)
This is the corresponding HTML:
{% extends "layout.html" %}
{% block content %}
{% if form %}
<form action="{{ url_for('add_book') }}" method="post">
{{ form.hidden_tag() }}
{{ form.title.label }}<br>
{{ form.title() }}<br>
{{ form.author.label }}<br>
{{ form.author(cols=32, rows=4) }}<br>
<!-- {{ form.category.label }}<br>
{{ form.category() }}<br> -->
{{ form.submit() }}
</form>
{% endif %}
{% endblock %}
When the page renders, the label and forms for the book and author appear, however on clicking Submit, the data does not get saved.
The code section is similar to that for registering a user and I am stuck on what to do because I cannot see any errors. I am using SQLite as a database.
Here is the book model:
class Book(db.Model):
__tablename__='books'
id=db.Column(db.Integer, primary_key=True)
title=db.Column(db.String(100))
author=db.Column(db.String(50))
# category=db.Column(db.String(50))
added_on=db.Column(db.DateTime, index=True, default=datetime.utcnow)
done=db.Column(db.Boolean, default=False)
user_id=db.Column(db.Integer, db.ForeignKey('users.id'))
def __init__(self, title, author, added_on, done, user_id):
self.title=title
self.author=author
self.added_on=added_on
self.done=done
self.user_id=user_id
def __repr__(self):
# return '<Book: Title - {0}, Author - {1}, Category - {2}>'.format(self.title, self.author, self.category)
return '<Book: Title - {0}, Author - {1}>'.format(self.title, self.author)
The current_user is a user proxy giving access to all user attributes or use something like this How to track the current user in flask-login?
a quick solution would be to change this line
user_id = current_user
into this
user_id = current_user.id
Update:
ok, I got it working. You need the following fixes, each of them leads to trouble with form validation and or committing to database:
- use current_user.id in your book object as I said earlier.
- removed the init method in books model. I'm not sure what the added value is at the moment, I'm getting error messages about fields added on and done which are not on the form. I haven't taken the time to look into it further.
- just go for if request.method=='POST' as you don't need both. The form will be checked for validation anyways.
tip: don't forget to create a requirements file (pip freeze --> requirements.txt), that makes it a lot easier to reinstall in a new virtual environment.

Symfony2 - Display data on same page

I am having a little trouble displaying data on the same page again. I have a simple view
{% block main %}
<div class="col-md-4">
<section class="panel panel-default">
<div class="panel-body">
<form action="{{ path('NickAlertBundle_tsubmit') }}" method="post" enctype="multipart/form-data" class="terminalForm" id="terminalForm">
<div class="row">
<div class="col-md-12">
<input type="text" class="addMargin" id="terminal_command" name="terminal_command" placeholder=">">
</div>
</div>
<div class="row">
<div class="col-md-8 col-md-offset-4">
<input type="submit" class="btn btn-default" id="terminal_submit" value="Submit">
</div>
</div>
</form>
</div>
</section>
</div>
<div class="col-md-8" id="terminal-window">
</div>
{% endblock %}
So on that view I display a form. The user enters some data and then I want the response display in the terminal-window div. So I have set up routes
NickAlertBundle_terminal:
pattern: /terminal
defaults: { _controller: NickAlertBundle:Alert:terminal }
methods: [GET]
NickAlertBundle_tsubmit:
pattern: /terminal
defaults: { _controller: NickAlertBundle:Alert:tcreate }
methods: [POST]
The GET simply renders the initial page, the POST controller is doing
public function terminalAction()
{
return $this->render('NickAlertBundle:Page:terminal.html.twig');
}
public function tcreateAction(Request $request)
{
try {
$terminal_command = strtoupper($request->get('terminal_command'));
$uapiService = $this->container->get('alert_bundle.api_service');
$commandData = $uapiService->terminalService($terminal_command);
return $this->render('NickAlertBundle:Page:terminal.html.twig', array(
'data' => $commandData,
));
}catch (Exception $e) {
}
}
Is this the correct way to do it? Reason I ask is because if I add the following to my div in the view
{% for d in data %}
{{ d }}
{% endfor %}
I obviously get the following error
Variable "data" does not exist in...
So how can I render the data that is returned from the form submission?
Thanks
This is because Twig expects data to be passed to the template the first time the page is rendered (which is handled by the initial GET controller). To remedy the issue, you need to check to determine if data has been defined.
I would do something like this:
{% if data is defined %}
{% for d in data %}
{{ d }}
{% endfor %}
{% endif %}
Now, when the form initially loads but is empty, Twig first checks to see if the variables was passed to it, and since it doesn't, it just skips the for loop altogether.
The other option would be to simply pass an empty array in your first controller. I would view it as less desirable unless you are persisting data and at that point it would be practical anyway.

Adding a CSS class to fields in django.contrib.auth.views.login

I'm still fairly new to django, and have come across Django forms for the first time through my use of the django.contrib.auth.views.login view, used when Django needs a user to authenticate.
I cannot however figure out how to add a CSS class to the username and password fields and the documentation doesn't specify how I can achieve it. Ideally I'd like to simply add the additional info to the template tag, such as {{ form.username | class="usernameclass" }} or whatever, or even write the field out manually, such as <input type="{{ form.password.type }}" name="{{ form.password.name }}" class="form-field-password"/>, but if I need to add a custom view to achieve this I can try that way.
The files related to this are below:
templates/login.html:
{% load url from future %}
...
<form method="post" action="{% url 'django.contrib.auth.views.login' %}">
{% csrf_token %}
<span class="heading">{{ form.username.label_tag }}</span><br/>
{{ form.username }}<br/>
<span class="heading">{{ form.password.label_tag }}</span><br/>
{{ form.password }}<br/>
<div id="login-button">
<input type="submit" value="Log In" />
<input type="hidden" name="next" value="{{ next }}" />
</div>
</form>
...
settings.py:
...
LOGIN_URL = '/login/'
...
urls.py
...
urlpatterns = patterns('',
url(r'^$', 'portal.views.home', name='home'),
url(r'^login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}),
url(r'^logout/$', 'django.contrib.auth.views.logout'),
...
)
Any advice is much appreciated!
This app will do exactly what you need.

Resources