I'm using flask-bootstrap to use the Bootstrap front-end for a flask web application. Unfortunately, since I've started using flask-bootstrap and flask-nav, I'm not able to display flash messages.
This is the base.html:
{% extends 'bootstrap/base.html' %}
{% block navbar %}
{{ nav.mynavbar.render() }}
{% endblock %}
<html>
<body>
<hr>
<div class='container'>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class=flashes>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endwith %}
{% block content %}{% endblock %}
</div>
</body>
</html>
This is one of the view that should flash a message when a change is saved:
#app.route('/model/<model_name>/edit', methods=['GET', 'POST'])
def edit(model_name):
"""Edit model's configuration.
Args:
model_name [str]: The name of the model we want to change the
configuration.
"""
# return to index page if model is not found in the database
model = DSModel.query.filter_by(name=model_name).first()
if not model:
flash('Model {} not found.'.format(model_name))
return redirect(url_for('index'))
# pre-load current model's configuration
form = ConfigurationForm()
# if it's a POST request, it means the user is trying to change the model's
# configuration. Save changes in the database
if request.method == 'POST': # and form.validate_on_submit():
model.configuration.configuration = form.value.data
model.configuration.datetime = datetime.datetime.utcnow()
db.session.add(model)
db.session.commit()
flash('Your changes have been saved.', 'success')
return redirect(url_for('edit', model_name=model_name))
else:
form.value.data = model.configuration.configuration
return render_template('edit.html', form=form)
Finally, this is the __init__.py:
from flask import Flask
from flask_bootstrap import Bootstrap
from flask_nav import Nav
from flask_nav.elements import Navbar, View
from flask_sqlalchemy import SQLAlchemy
nav = Nav()
#nav.navigation()
def mynavbar():
return Navbar(
'Dashboard',
View('Home', 'index'),
View('Login', 'login')
)
app = Flask(__name__)
Bootstrap(app)
nav.init_app(app)
app.config.from_object('config')
db = SQLAlchemy(app)
from app import views, models
I think there must be something funky with my base.html file, but I'm not terribly familiar with HTML, so I'm not able to find what's wrong. I've looked into examples online (i.e. here), but the format seems to be pretty similar to what I'm doing.
EDIT: This is the edit.html file:
{% extends 'base.html' %}
{% block content %}
<h1>Update configuration</h1>
<form action='' method='post' name='configuration'>
<p>
Please update the current model configuration:<br>
{{ form.value(cols='150', rows='20') }}
<p><input type='submit' value='Save'></p>
</form>
{% endblock %}
Try to edit your base.html to this:
{% extends 'bootstrap/base.html' %}
{% block navbar %}
{{ nav.mynavbar.render() }}
{% endblock %}
<html>
<body>
<hr>
<div class='container'>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class=flashes>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
</div>
{% block content %}{% endblock %}
</div>
</body>
</html>
Related
One of functionality in my training project:
subscribe to the news by check-box and e-mail.
Send newsletter daily.
The user can unsubscribe from the mailing list in his profile by unchecking the checkbox.
It so happened that first I set up a daily newsletter for users who have booleanfield = true.
For it I marked the checkboxes in the admin panel. It works.
Now it is necessary to add the checkbox and the mail field to the news page.
I'm stuck on the simplest. Tired and confused.
Please help me place a checkbox and a mail box with a send button on the news page
models.py
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
hr = models.BooleanField(default=False)
subscribed_for_mailings = models.BooleanField(default=False)
subscription_email = models.EmailField(default="")
def __str__(self):
return str(self.user)
Forms.py
class MailingForm(forms.ModelForm):
class Meta:
model = models.Profile
fields = ('subscription_email', 'subscribed_for_mailings', )
widgets = {
'subscription_email': forms.EmailInput(attrs={"placeholder": "Your Email..."}),
'subscribed_for_mailings': forms.CheckboxInput,
}
views.py
def all_news(request):
today = date.today()
today_news = models.TopNews.objects.filter(created__gte=today)
return render(request, "news.html",
{'today_news': today_news})
def mailing_news(request):
if request.method == 'POST':
mailing_form = forms.MailingForm(request.POST)
if mailing_form.is_valid():
mailing_form.save()
return HttpResponse('You will receive news by mail')
else:
mailing_form = forms.MailingForm()
return render(request, "news.html", {'mailing_form': mailing_form})
urls.py
...
path('news/', views.all_news, name='all_news'),
...
news.html
{% extends 'base.html' %}
{% block title %}
News
{% endblock %}
{% block body %}
<h1>Last news</h1>
{% for news in today_news%}
<h3>{{ news.title }}</h3>
Read this news
<p>
{{ news.created }}
</p>
<hr>
{% endfor %}
<h4>I want to receive news by mail</h4>
<form action="." method="post">
{{ mailing_form.as_p }}
{% csrf_token %}
<label>
<input type="submit" value="Subscribe">
</label>
</form>
{% endblock %}
The page displays a list of news and only the "send" button. There is no check-box and a field for mail
enter image description here
Finally I realized this functionality in a different way:
forms.py
class MailingForm(forms.ModelForm):
class Meta:
model = models.Profile
fields = ('subscribed_for_mailings', 'subscription_email', )
views.py
#login_required
def mailing_news(request):
if request.method == "POST":
mailing_form = forms.MailingForm(request.POST,
instance=request.user.profile,
)
if mailing_form.is_valid():
mailing_news = mailing_form.save(commit=False)
mailing_news.subscribed_for_mailings = mailing_news.subscribed_for_mailings
mailing_news.subscription_email = mailing_news.subscription_email
mailing_news.save()
return render(request, "subscribe_complete.html",
{"mailing_news": mailing_news})
else:
mailing_form = forms.MailingForm()
return render(request, 'subscribe.html', {"mailing_form": mailing_form})
news.html
{% extends 'base.html' %}
{% block title %}
News
{% endblock %}
{% block body %}
<h1>Last news</h1> {{ news.created }}
{% for news in today_news%}
<h3>{{ news.title }}</h3>
Read this news
<hr>
{% endfor %}
I want to receive news by mail
{% endblock %}
urls.py
...
path('subscribe/', views.mailing_news, name='subscribe')
...
news.html
{% extends 'base.html' %}
{% block title %}
News
{% endblock %}
{% block body %}
<h1>Last news</h1> {{ news.created }}
{% for news in today_news%}
<h3>{{ news.title }}</h3>
Read this news
<hr>
{% endfor %}
I want to receive news by mail
{% endblock %}
subscribe.html
{% extends 'base.html' %}
{% block title %}
Subscribe
{% endblock %}
{% block body %}
<form action="." method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ mailing_news.as_p }}
{% if user.profile.subscribed_for_mailings is True %}
<input type="checkbox" name="subscribed_for_mailings" id="id_subscribed_for_mailings" checked="">
If you don't want to receive emails anymore, uncheck
<br>
Subscription email: <input type="email" name="subscription_email" value={{ user.profile.subscription_email }} class="vTextField" maxlength="254" id="id_subscription_email">
{% else %}
<label>
<input type="checkbox" name="subscribed_for_mailings" id="id_subscribed_for_mailings">
I want to subscribe for mailing news
</label>
<p><label>
Send news on my email:
<input type="email" name="subscription_email" class="vTextField" maxlength="254" id="id_subscription_email">
</label></p>
{% endif %}
<p><input type="submit" value="Update"></p>
</form>
{% endblock %}
subscribe_complete.html
{% extends 'base.html' %}
{% block title %}
Subscribing complete
{% endblock %}
{% block body %}
<h3>Hi {{ user.username }}</h3>
Thanks for subscribing.
You will receive daily news by email: {{ user.profile.subscription_email }}
{% endblock %}
you need to change subscribed_for_mailings in mailing news, like this
def mailing_news(request):
if request.method == 'POST':
mailing_form = forms.MailingForm(request.POST)
if mailing_form.is_valid():
profile = mailing_form.save(commit=False) ####
profile.subscribed_for_mailings = mailing_form.cleaned_data.get('subscribed_for_mailings') ####
profile.subscription_email = mailing_form.cleaned_data.get('subscription_email') ####
profile.save() #### new_line
return HttpResponse('You will receive news by mail')
else:
mailing_form = forms.MailingForm()
return render(request, "news.html", {'mailing_form': mailing_form})
you can change in cleaned_data.get('....')
I'm trying to follow https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-iii-web-forms tutorial with slight modifications (I'm trying to use it for my homework task). I'm simply trying to modify it, so I'll get form data and then process it. So far I'm just trying to flash the data, later I want to redirect to another page and display the results there. The problem is, whatever I write in the form does nothing - I just get redirected to the main page, where the form is. It even does not get cleared! What am I doing wrong? So far I have:
Directories structure:
homework:
-app:
-templates:
-base.html
-index.html
-__init__.py
-forms.py
-routes.py
-config.py
-main.py
config.py contains only Config class with some constants as attributes, so I didn't include it, and main.py only imports app.
base.html:
<html>
<head>
<title>Weather consultant</title>
</head>
<body>
<div>
Weather consultant:
Home
</div>
<hr>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</body>
</html>
index.html:
{% extends "base.html" %}
{% block content %}
<h1>Enter query</h1>
<form action="" method="post" novalidate>
<p>
{{ form.city.label }}<br>
{{ form.city()}}
</p>
<p>
{{ form.date.label }}<br>
{{ form.date() }}
</p>
<p>{{ form.use_dark_sky() }}
{{ form.use_dark_sky.label }}</p>
<p>{{ form.use_storm_glass() }}
{{ form.use_storm_glass.label }}</p>
<p>{{ form.use_weather_stack() }}
{{ form.use_weather_stack.label }}</p>
<p>{{ form.use_yahoo() }}
{{ form.use_yahoo.label }}</p>
<p>{{ form.use_open_weather() }}
{{ form.use_open_weather.label }}</p>
<p>{{ form.use_weather_bit() }}
{{ form.use_weather_bit.label }}</p>
<p>{{ form.use_visual_crossing() }}
{{ form.use_visual_crossing.label }}</p>
<p>{{ form.submit() }}</p>
</form>
{% endblock %}
__init__.py:
from flask import Flask
from config import Config
app = Flask(__name__)
app.config["SECRET_KEY"] = "not-so-secret"
config = Config()
from app import routes
forms.py:
class UserInputForm(FlaskForm):
city = StringField("City")
date = StringField("Enter desired date (format DD/MM/YYYY)")
use_dark_sky = BooleanField("Use DarkSky API")
use_storm_glass = BooleanField("Use Storm Glass API")
use_weather_stack = BooleanField("Use WeatherStack API")
use_yahoo = BooleanField("Use Yahoo Weather API")
use_open_weather = BooleanField(
"Use OpenWeather API - only current and near future data")
use_weather_bit = BooleanField(
"Use WeatherBit API - only current and future data")
use_visual_crossing = BooleanField("Use VisualCrossing API")
submit = SubmitField("Search")
routes.py:
#app.route("/", methods=["GET", "POST"])
def index():
form = UserInputForm()
if form.validate_on_submit():
session["form"] = form
flash('Data requested for city {}, date={}'.format(
form.city.data, form.date.data))
return redirect(url_for("index"))
return render_template("index.html", form=form)
The initial problem was with CSRF key, it turns out that API has changed recently (and silently), see https://flask-wtf.readthedocs.io/en/stable/csrf.html. Edited part of __init__.py:
app = Flask(__name__)
app.config['SECRET_KEY'] = "not-so-secret"
csfr = CSRFProtect(app)
config = Config()
Thanks to #snakecharmerb for providing the debugging advice.
I am learning Flask and trying build a very simple app which has few parts creating new users and searching the existing users. The create/register new users part is working just fine, but for some reason the search function is not working as expected because the form is not getting submitted. I have tried to look every possible case which I think of, searched Stackoverflow as well but could not get to fix it.
The code for registration functionality:
forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired, length
class Register(FlaskForm):
name = StringField('name', validators=[DataRequired(), length(min=1, max=30)])
email = StringField('email', validators=[DataRequired()])
submit = SubmitField('Register')
class UserSeacrh(FlaskForm):
name = StringField('name', validators=[DataRequired()])
email = StringField('email', validators=[DataRequired()])
submit = SubmitField('Search')
views.py
#app.route("/register", methods=['GET', 'POST'])
def register():
form = Register()
if form.validate_on_submit():
db.create_all()
user = CreateUser(form.name.data, form.email.data)
db.session.add(user)
db.session.commit()
flash('User {} created successfully'.format(form.name.data))
return redirect(url_for("register"))
return render_template("register.html", form=form, title='New User Registration')
#app.route("/search", methods=['GET', 'POST'])
def user_profile():
form = UserSeacrh()
if form.validate_on_submit():
flash('{}'.format(user))
return redirect(url_for("home"))
#return render_template("users.html", users=user)
return render_template("userSearch.html", form=form)
register.html
<!DOCTYPE html>
{% extends "base.html" %}
{% block body %}
<form action="" method="post">
{{ form.hidden_tag() }}
<div>
<h4>User Registeration</h4>
<span>Name {{form.name}}</span>
<span style="color: red">
{% for error in form.name.errors %}
{{error}}
{% endfor %}
</span
<span>Email {{form.email}}</span>
<span style="color: red">
{% for error in form.email.errors %}
{{error}}
{% endfor %}
</span>
</div>
{{form.submit()}}
</form>
{% with messages = get_flashed_messages() %}
{% if messages %}
<br/>
<ul>
{% for message in messages %}
<li>{{message}}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% endblock %}
userSearch.html
<!DOCTYPE html>
{% extends "base.html" %}
{% block body %}
<form action="" method="post">
{{ form.hidden_tag() }}
<h4>User Search Form</h4>
<div>
<span>Email {{form.email}}</span>
<span style="color: red">
{% for error in form.email.errors %}
{{error}}
{% endfor %}
</span>
</div>
{{form.submit()}}
</form>
{% with messages = get_flashed_messages() %}
{% if messages %}
<br/>
<ul>
{% for message in messages %}
<li>{{message}}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% endblock %}
I am clueless now, can someone please help me out here?
Most likely the reason is that in the userSearch.html you didn't add the name field. In the UserSeacrh class the field name has a validator DataRequired which most likely creates the problem. Just remove the name field in the UserSeacrh class if you want to do the search by email only.
By the way there is a typo in UserSeacrh - it should be UserSearch. But in your case it's not the problem.
I think you need to specify the action for your form, i.e., what URL to POST the completed form to.
<form action="" method="post">
I was able to solve this using Nurzhan' tip by removing the name field from UserSearch form from forms.py .
I'm trying to incorporate an template tag/inclusion tag into my sidebar for the site. The main section of the page updates properly when I put:
{% if user.is_authenticated %}
<h1> Hello {{ user.username }}
{% else %}
<h1> Hello </h1>
{% endif %}
When I try to use the same principle in my template tag/sidebar, it seems to ignore user.is_authenticated and will always show 'login' and 'register', when it should be just showing 'logout'.
The body of the html (main index page):
{% load Kappa_extras %}
<body>
<div class="container-fluid">
<div class="row">
<div class="col-sm-2" id="side_section">
{% block sidebar %}
{% get_game_list %}
{% endblock %}
</div>
<!--Main section-->
<div class="col-sm-10" id="main_section">
{% block body %}
{% endblock %}
</div>
</div>
</div>
The get_game_list function from 'Kappa_extras':
from django import template
from Kappa.models import Game, Game_Page
from django.contrib.auth.models import User
register = template.Library()
#register.inclusion_tag('Kappa/sidebar.html')
def get_game_list():
return {'game_list': Game.objects.all()}
and the 'Kappa/sidebar.html':
<div id="side_default_list">
<ul class="nav">
<li>Kappa</li>
{% if user.is_authenticated %}
<li>Log Out</li>
{% else %}
<li>Log In</li>
<li>Register</li>
{% endif %}
</div>
I checked a few older inquires though none of them are working properly. I tried putting request into def get_game_list(request): but it just said did not receive value for the argument. How do I get the sidebar to update properly when user.is_authenticated?
You need to pass the user to your inclusion tag.
#register.inclusion_tag('Kappa/sidebar.html')
def get_game_list(user):
return {'game_list': Game.objects.all(), 'user': user}
Then in your template, call the tag with
{% get_game_list user %}
Alternatively, you can set takes_context=True in your inclusion tag, so that you can access the user from the template context.
#register.inclusion_tag('Kappa/sidebar.html', takes_context=True)
def get_game_list(context):
return {'game_list': Game.objects.all(), 'user': context['user']}
In this case, you don't need to pass the user to the template tag any more.
{% get_game_list %}
See the docs for more information and other examples.
I've simple 2 line code :
#app.route('/contact/')
def contact():
flash('We are reachable at ')
return render_template('contact.html')
I get the message 'We are reachable at' at /contact but it appears are normal text message. It doesn't background color(blue) or disappears after seconds.
where contact.html contains
{% extends "layout.html" %}
{% block title %}Contact{% endblock title %}
{% block body %}
<h2> Contact Us </h2>
Your email address must be valid as this is where reply
will be sent. We do not share this address with anybody.
{% endblock body %}
Please have a look at this. this might help you
<!doctype html>
<title>My Application</title>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class="flashes">
{% for message in messages %}
<div class="message_flash">{{ message }}</div>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% block body %}
{% endblock %}
and Do some styling with the css
p {
color:blue;
}
And add some jquery to the code
$(function() {
// setTimeout() function will be fired after page is loaded
// it will wait for 5 sec. and then will fire
// $(".message_flash").hide() function
setTimeout(function() {
$(".message_flash").hide('blind', {}, 500)
}, 5000);
})
Hope this helps you.
I think what you need is some CSS to make it look nice. If you add some bootstrap to your base.html/layout.html, you can do this in base.html/layout.html.
{% with messages=get_flashed_messages(with_categories=true) %}
{% for category, message in messages %}
<div class='alert alert-{{category}} text-center alert-dismissible fade show m-auto'>
{{ message }}
</div>
{% endfor %}
{% endwith %}
And now whenever you are to display a flash message, do this in your route.
#app.route('/')
def index():
flash('Your message here', 'your bootstrap category[eg:success, primary, etc]')
return reder_template('contact.html')