So I've been working w/ Flask & Bootstrap on an Apache Server. I've gotten it to the point where I can access the app & render the "first" or "main" template w/ the following route:
from view.py:
#app.route('/')
def fn_home():
return render_template("main.html")
Unfortunately, every attempt to route to another webpage/function from main.html fails. I'm using the "url_for" function in the navbar list href, attempting to get flask to supply the xls-upload.html webpage to Apache.
from main.html:
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li>Upload Spreadsheets </li>
from view.py:
#app.route('/upload')
def upload():
return render_template("xls-upload.html")
It looks like the function is being engaged, since the URL changes to http://myapp/upload, but the html page is NOT rendered/returned by the function - instead I receive a 404 "Not Found". I can't seem to return anything from the function, even return "Hello World".
It "seems" like Apache is really trying to resolve the http://myapp/upload path, rather than having a socket opened up to the Flask application through which the html is then sent. I'm not sure if this is a FCGI problem, if I'm missing a relative/absolute path issue, misunderstanding how Flask works in general, or some combination of all, etc.
I'm new to Flask so I'm hoping that someone could help me along the way since I really feel I've come to a dead end.
Thanks in advance!
My flask app is structured as follows:
var/www/cgi-bin/myapp/ (root dir)
start.fcgi
view.py (the flask routing/app file)
static (dir)
bootstrap files
templates (dir)
main.html
xls-upload.html
Here are my applicable files:
1) /etc/httpd/conf.d/myapp:
<VirtualHost *:80>
ServerAdmin webmaster#localhost
DocumentRoot /var/www/cgi-bin/myapp/static/
ServerName myapp
Alias /static/ /var/www/cgi-bin/myapp/static/
ScriptAlias / /var/www/cgi-bin/myapp/start.fcgi
<Directory "var/www/cgi-bin/myapp">
AllowOverride None
Order allow,deny
Allow from all
AuthType Basic
AuthUserFile /etc/httpd/.htpasswd
AuthName 'Enter Password'
Require valid-user
</Directory>
</VirtualHost>
2) /var/www/cgi-bin/myapp/start.fcgi:
#!/usr/bin/python
# IMPORTS:
from flup.server.fcgi import WSGIServer
from view import app
if __name__ == '__main__':
WSGIServer(app).run()
3) /var/www/cgi-bin/myapp/view.py:
#!/usr/bin/python
# IMPORTS:
import os
from flask import Flask, render_template, url_for, request, session, redirect
from werkzeug import secure_filename
# STATIC VARIABLES
UPLOAD_FOLDER = 'var/www/cgi-bin/myapp/xls-dir'
ALLOWED_EXTENSIONS = set(['xls'])
## flask:
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
# FUNCTIONS
def fn_allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
#app.route('/')
def fn_home():
return render_template("main.html")
#app.route('/upload')
def upload():
return render_template("xls-upload.html")
#return "HI there"
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
4) /var/www/cgi-bin/myapp/templates/main.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>ALG Tools HOME</title>
<!-- Bootstrap -->
<link href="{{ url_for('static', filename = 'css/bootstrap.min.css') }}" rel="stylesheet">
</head>
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">ALG Tool - HOME</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li>Upload Spreadsheets </li>
<li>Download Spreadsheets</li>
<li>Generate Configs</li>
</ul>
</div>
</div>
</nav>
<body>
<h2>ALG stuff</h2>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="{{ url_for('static', filename = 'js/bootstrap.min.js') }}"></script>
</body>
</html>
5) /var/www/cgi-bin/myapp/templates/xls-upload.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>ALG XLS Upload</title>
<!-- Bootstrap -->
<link href="{{ url_for('static', filename = 'css/bootstrap.min.css') }}" rel="stylesheet">
</head>
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">ALG Tool - HOME</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li>Upload Spreadsheets </li>
<li>Download Spreadsheets</li>
<li>Generate Configs</li>
</ul>
</div>
</div>
</nav>
<body>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="{{ url_for('static', filename = 'js/bootstrap.min.js') }}"></script>
</body>
</html>
FCGI isn't really a recommended way to serve a Python web app. You should look into one of the many ways of running WSGI.
However, assuming you need to do this for some reason, you have a minor configuration issue which is the cause of your problem; you need a trailing slash on the ScriptAlias path.
ScriptAlias / /var/www/cgi-bin/myapp/start.fcgi/
With this, Apache will pass the full path to the start.fcgi script, instead of replacing it.
Note that even with FCGI, you should not put your app code in cgi-bin. It doesn't need to be there, as it isn't run by the web server like a CGI app. In fact, your code should not even be under /var/www at all.
Related
I am ordering the query result using time but I want to give the user the ability to choose the way he wants to order data lets say he wants to use alphabetical order or he wants to order with ascending or descending order I want to know how to that in flask, sorry for my bad English
this is my code
#routes.route('/posts')
def show_posts():
page=request.args.get('page',1,type=int)
posts=Posts.query.order_by(Posts.timestamp.desc).paginate(page,per_page=10)
return render_template('routes/show_posts.html',posts=posts)
ok, so this is my first flask answer (I only yesterday finished tutorials):
EDIT/INFO: at the end I didn't use any forms to accomplish this, just simple routes, but forms could be used too, this just seemed a bit more simple (more because I couldn't figure out how to use those forms for this :))
EDIT2/INFO: also I don't think for this particular code there is any need for that methods argument in decorators so that could probably be removed for this specific code
the main file (it contains everything because that was easier than to show each module I would have used)
from flask import Flask, render_template, url_for
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
db = SQLAlchemy(app)
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
content = db.Column(db.Text, nullable=False)
#app.route('/posts/filter_by/<string:key>')
#app.route('/posts', methods=['GET', 'POST'])
#app.route('/')
def all_posts(key=None):
posts = Post.query.order_by(Post.title.asc()).all()
if key == 'ZA':
posts = Post.query.order_by(Post.title.desc()).all()
return render_template('posts.html', posts=posts)
if __name__ == '__main__':
app.run(debug=True)
and here is the template (uses bootstrap stuff):
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<title>Hello, world!</title>
</head>
<body>
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle"
type="button" id="dropdownMenu1" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
Sort by
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenu1">
<a class="dropdown-item" href="{{ url_for('all_posts', key='AZ') }}">A-Z</a>
<a class="dropdown-item" href="{{ url_for('all_posts', key='ZA') }}">Z-A</a>
</div>
</div>
{% for post in posts %}
<div class="card">
<div class="card-body">
<h4 class="card-title">{{ post.title }}</h4>
<p class="card-text">{{ post.content }}</p>
</div>
</div>
{% endfor %}
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>
So the first thing (top-down):
import all that is needed
then initialize the Flask and SQLAlchemy classes and also config the app to the database
Create the post model for storing posts and stuff (that I don't exactly know)
So then comes the main part - the route.
So first of I create a route with a variable:
#app.route('/posts/filter_by/<string:key>')
this will allow to request this URL and be able to get additional information (from that variable) that will help with handling the response
then add more routes so that the url looks cleaner and that is pretty much the only reason (as far as I know)
then define the function:
name it what You feel like but You have to pass the variable as an argument and since multiple routes are used and probably for other reasons too set a default value for that argument so that it is not necessary to be provided
then using simple if statements and using that variable handle how posts are ordered
then return the template including those posts in that order
Now about the template
First of it uses bootstrap stuff and I got the most code from there (just copy pasted from their website) or here which is a nice cheatsheet.
So I copied the dropdown menu from that cheatsheet and just changed some values, most notably the href attribute:
Those I replaced with url_for functions and passed the variable too as You can see so that the request sent is with that variable that will allow to handle how posts are ordered
Hope all is clear, if You have any more questions, ask them.
first thing first Matiiss your answer is very good thanks for the help, now I have found another way it has some similarities to Matiiss answer i want to share it so if anyone found this question now you have two answers to choose from.
#routes.route('/posts')
def show_posts():
posts= Posts.query.order_by(Posts.name.desc()).all()
filter_rule = request.args.get('filter')
if filter_rule == 'A-Z':
posts= Posts.query.order_by(Posts.name).all()
return render_template('posts.html',posts=posts)
HTML part
<div class="row">
<div class="col-md-3">
<div class="nav nav-pills flex-column" role="tablist" aria-orientation="vertical">
<a class="nav-item nav-link"
href="{{ url_for('.show_posts', filter='A-Z') }}">
A-Z
</a>
<a class="nav-item nav-link"
href="{{ url_for('.show_posts', filter='Z-A') }}">
Z-A
</a>
</div>
</div>
I'm trying to render this HTML File (An Home page) And I get an error that template is not found.
#views.py
from django.shortcuts import render
def index(request):
"""Homepage"""
return render(request,'templates/index.html')
from django.contrib import admin
from django.urls import path, include
from . import views
urlpatterns = [
path('', views.index, name='Home'),
]
error:
TemplateDoesNotExist at /
templates/index.html
and this just loads a blank page:
from django.shortcuts import render
def index(request):
"""Homepage"""
return render(request, 'index.html')
My HTML File
I'm guessing maybe some kind of link is missing here.
I've also added 'os.path.join(BASE_DIR,"templates")' to DIRS and setting and the page is still blank.
<link href="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
Home.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<title>Triangulation Calculator</title>
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
<div class="container">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home
<span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Three Positions Triangulation</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Second </a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Add Known Location</a>
</li>
</ul>
</div>
</div>
</nav>
<section class="py-5 text-center">
<div class="container">
<h2 class="text-center">Triangulation Calculator</h2>
<p class="text-muted mb-5 text-center">There's three Features here, below, you'll find explaintion for each.</p>
<div class="row">
<div class="col-sm-6 col-lg-4 mb-3">
<svg class="lnr text-primary services-icon">
<use xlink:href="#lnr-magic-wand"></use>
</svg>
<h6>Three Positions Triangulation</h6>
<p class="text-muted">Naming is All, Choose a grate name for your mission so you can come back and open that map whenever you want.
You input the latitude and longitude for GDT 1, GDT 2 and the location of the UAV, also, we need the
elevation of the uav above sea level, where do you get that data?
Thank God for Google.
go to google maps, when you press a location on the map you can the coordinates as we need them, in the following format:
31.4531,35.56243.
first is latitude and longitude, copy the values to calculator.
done?
press POST
the page will refresh and you'll see all your data.
go to the address line and add the mission name to the and of the line.
KABLAM!
Your map will open.</p>
</div>
<div class="col-sm-6 col-lg-4 mb-3">
<svg class="lnr text-primary services-icon">
<use xlink:href="#lnr-heart"></use>
</svg>
<h6>Second GDT options</h6>
<p class="text-muted">Second option works a lot the same: Input your mission name and the data for GDT 1 and the UAV, and choose the area of the mission.
and the rest is the same.
How does the map work here?
if you hover your mouse over one of the numbers you'll see the boundaries of that triangulation, the more you zoom in,
the more detailed it gets.</p>
</div>
<div class="col-sm-6 col-lg-4 mb-3">
<svg class="lnr text-primary services-icon">
<use xlink:href="#lnr-rocket"></use>
</svg>
<h6>Add Location Info to the DataBase</h6>
<p class="text-muted">Here you input a base,outpost,mountain or just every location you ever put a GDT in.
choose the area where that position lies.
and every time someone will use the second option, we'll automatically add those positions to the map.</p>
</div>
</div>
</div>
</div>
</section>
</body>
</html>
You have to create templates folder on same level of app not in the app, and set TEMPLATES variable in settings.py
settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
Now, you can add index.html in templates folder or you can add index.html file in an appropriate folder and add that folder in the templates folder. Folder structure is like below...
app_1
|
|
app_2
|
|
templates
|
|__index.html
Check whether you have added the template_dir, if not add this in your settings.py below the BASE_DIR
TEMPLATE_DIR = os.path.join(BASE_DIR,'templates')
and find templates and dirs as a dictionary file in the settings.py, add this
DIRS = [TEMPLATE_DIR,]
or directly you can add in DIRS like this
DIRS = [os.path.join(BASE_DIR,'templates')]
and make sure the directory name is templates not template according to my answer
I had code that worked perfectly fine, then I wanted to use flask, so I copied it into a flask app directory. The html code is below:
<html>
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
crossorigin="anonymous">
</head>
<body>
<div id="app" class="container">
<div class="row">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item" v-for="tab in tabs" v-bind:class="tab.active">
{{ tab.name }}
</li>
</ul>
</div>
</nav>
</div>
<div class="row">
<div class="col">
<hr class="navbarDivide">
</div>
</div>
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="/static/js/challenges.js"></script>
</body>
</html>
When I remove the stuff for Vue, it works perfectly fine (when I remove the v-for, v-bind, and {{ tab.name }}. However, when I add it, it gives me a 500 error. I'm doing all of this using flask. Flask code below:
from flask import Flask, render_template
app = Flask(__name__)
application = app
#app.route('/base')
def index():
return render_template('base.html')
if __name__ == '__main__':
app.run(debug=True)
The javascript code just has the required stuff for Vue.js (the object with the data). The javascript code is below:
var app = new Vue({
el: '#app',
data: {
tabs: [
{ name: "Home", active: "" },
{ name: "Challenges", active: "active" },
{ name: "Scoreboard", active: "" },
{ name: "About", active: "" }
]
}
});
Update:
After a little more debugging, I think I may have figured out the problem. When I comment out all the stuff, and add console.log("it works"); to my javascript code, nothing happens. That probably means the javascript code isn't connecting to the html, but how can I solve that?
I found the solution. I was manually putting the url of the javascript
<script src="/static/js/challenges.js"></script>
What I had to do to fix it was use url_for
<script src="{{ url_for('static', filename='js/challenges.js') }}"></script>
Probably something a lot of people that have used flask before know, but I'm new to this.
I began switching from using standard basic SQL in my flask app to using peewee and am getting a weird bug I cant seem to find any info about. My endpoints are working fine but when I tried going to the landing page I get "jinja2.exceptions.UndefinedError: 'peewee.IntegerField object' has no attribute 'flags'"
This seems like some weird interaction with wtforms and peewee but I cant seem to find similar issues. Thanks in advance.
Note everything is in one file
My Models:
class pipelineForm(FlaskForm):
pipeline = IntegerField('Pipeline ID')
class Process(Model):
pipeline_id = IntegerField()
process_name= CharField(null = True)
log= CharField(null = True)
exit_code= IntegerField()
started= CharField(null = True)
finsihed= CharField(null = True)
class Meta:
database=db
End Point for Landing Page:
#app.route('/bloodhound', methods=['GET','POST'])
def index():
form =pipelineForm()
print(form.errors)
if form.validate_on_submit():
print(str(form.pipeline.data))
return redirect(url_for('.display', pipelineId=form.pipeline.data))#'<h1>' + str(form.pipeline.data) + '</h1>'
return render_template('index.html',form=form)
Landing Page:
{% extends "bootstrap/base.html" %} {%import "bootstrap/wtf.html" as wtf%} {% block content %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="../../favicon.ico">
<title>Narrow Jumbotron Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link href="../../dist/css/bootstrap.min.css" rel="stylesheet">
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
<link href="../../assets/css/ie10-viewport-bug-workaround.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="jumbotron-narrow.css" rel="stylesheet">
<!-- Just for debugging purposes. Don't actually copy these 2 lines! -->
<!--[if lt IE 9]><script src="../../assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
<script src="../../assets/js/ie-emulation-modes-warning.js"></script>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/bloodhound">Bloodhound</a>
</div>
<ul class="nav navbar-nav">
<li class="active">Home</li>
<li>Performance</li>
</ul>
</div>
</nav>
<body>
<div class="container">
<div class="jumbotron">
<h1>Welcome to Bloodhound!</h1>
<p class="lead">Enter a pipeline Id to get diagnostic information.</p>
<form class="input" method="POST" action="/bloodhound">
<div class="input-group" style="width: 300px;">
{{form.hidden_tag()}} {{wtf.form_field(form.pipeline)}}
<span class="input-group-btn" style="vertical-align: bottom;">
<button class="btn btn-default" type="submit" >Go!</button>
</span>
</div>
</form>
</div>
<footer class="footer">
<p>© 2017 MITRE.</p>
</footer>
</div>
<!-- /container -->
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
<script src="../../assets/js/ie10-viewport-bug-workaround.js"></script>
</body>
</html>
{% endblock %}
Full Stack Trace
Traceback (most recent call last):
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/flask/app.py", line 1997, in __call__
return self.wsgi_app(environ, start_response)
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/flask/app.py", line 1985, in wsgi_app
response = self.handle_exception(e)
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/flask/app.py", line 1540, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/flask/_compat.py", line 33, in reraise
raise value
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/flask/app.py", line 1982, in wsgi_app
response = self.full_dispatch_request()
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/flask/app.py", line 1614, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/flask/app.py", line 1517, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/flask/_compat.py", line 33, in reraise
raise value
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/flask/app.py", line 1612, in full_dispatch_request
rv = self.dispatch_request()
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/flask/app.py", line 1598, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/patrick/process_tracker/api/tracker_api.py", line 201, in index
return render_template('index.html',form=form)
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/flask/templating.py", line 134, in render_template
context, ctx.app)
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/flask/templating.py", line 116, in _render
rv = template.render(context)
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/jinja2/environment.py", line 1008, in render
return self.environment.handle_exception(exc_info, True)
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/jinja2/environment.py", line 780, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/jinja2/_compat.py", line 37, in reraise
raise value.with_traceback(tb)
File "/home/patrick/process_tracker/api/templates/index.html", line 1, in top-level template code
{% extends "bootstrap/base.html" %} {%import "bootstrap/wtf.html" as wtf%} {% block content %}
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/flask_bootstrap/templates/bootstrap/base.html", line 1, in top-level template
code
{% block doc -%}
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/flask_bootstrap/templates/bootstrap/base.html", line 4, in block "doc"
{%- block html %}
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/flask_bootstrap/templates/bootstrap/base.html", line 20, in block "html"
{% block body -%}
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/flask_bootstrap/templates/bootstrap/base.html", line 23, in block "body"
{% block content -%}
File "/home/patrick/process_tracker/api/templates/index.html", line 58, in block "content"
<!-- {{form.hidden_tag()}} {{wtf.form_field(form.pipeline)}} -->
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/jinja2/runtime.py", line 553, in _invoke
rv = self._func(*arguments)
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/flask_bootstrap/templates/bootstrap/wtf.html", line 36, in template
{% if field.flags.required and not required in kwargs %}
File "/home/patrick/enviroments/venv/lib/python3.5/site-packages/jinja2/environment.py", line 430, in getattr
return getattr(obj, attribute)
According to your error message this field
class pipelineForm(FlaskForm):
pipeline = IntegerField('Pipeline ID')
is of type pewee.IntegerField and you wan it to be the IntegerField type of WTForms. If you have both classes in the same file you need to:
import pewee
import wtforms.fields
class pipelineForm(FlaskForm):
pipeline = fields.IntegerField('Pipeline ID')
class Process(Model):
pipeline_id = pewee.IntegerField() # and so on
I'm very new at Pyramid, I have used Django in the past, but I can't find a clean explanation of how to use base templating in Pyramid Chameleon templates.
I have a very simple .pt file which I want to be my base.pt template it's something like this:
<link href="static/bootstrap/css/bootstrap.css" rel="stylesheet">
<head>
</head>
<body>
<header class="navbar navbar-inverse navbar-fixed-top bs-docs-nav" role="banner">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggle" type="button" data-toggle="collapse" data-target=".bs-navbar-collapse">
<span class="sr-only">Toggle navigation</span>
</button>
My project
</div>
</div>
</header>
</body>
</html>
As you can see I try to have bootstrap header in all the following templates of my project, so what do I need to have so that all templates inherit or have base.pt as base template ? In Django I will just use {% include base.html %}
Chameleon and Mako are the two templating languages with support currently bundled within Pyramid. However, Jinja2 is officially supported by the pyramid_jinja2 addon and is easily activated. Jinja2 provides a syntax very similar to Django's if you do not wish to learn Chameleon.
config.include('pyramid_jinja2')
#view_config(..., renderer='myapp:templates/home.jinja2')
def view(request):
return {}