I have a flask route search that serves json search results and an index one that serves a page to search from, simplified as
#app.route('/search')
def search():
res = querydb(request.args)
return jsonify(res)
#app.route('/index')
def index():
return render_template('index.html')
In index.html, I have search forms linked to angular variables, and a button that queries /search using angular's $http and url params from the search forms.
I would like the ability to additionally fetch initial results based on the url (for example, let the url /index?color=red load the /index page and fetch results from /search?color=red on load).
To do this, I'm redefinig the jinja template tags as <%blah%> (to not interfere with angular's), and rendering the page with render_template('index.html', color='red'), with a snippet in the html like
<div ng-controller="MainCtrl" ng-init="fetch('<%color%>')"> </div>
There mustbe a better way to send the params from flask to angular (trying $routeParams or $location.search() doesn't seem to work with flask, returning empty objects). Or should I be composing the views differently somehow?
You should handle your page routes from angular and your API endpoints from flask. So your flask file might look like:
#app.route('/api/search')
def search():
res = querydb(request.args)
return jsonify(res)
#app.route('/')
def index():
return render_template('index.html')
Angular App
var app = angular.module('myApp', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider
.when('/index', {
templateUrl: 'mainView.html'
controller: 'MainCtrl'
});
});
controller
var MainCtrl = function($location, $http, $scope) {
//Now you can access the search params
var searchParams = $location.search();
$http.get('/api/search?color=' + searchParams.color).success(function(data) {
$scope.results = data;
});
}
Now if you go to http://somedomain/#/index?color=red it should fetch the initial results. Note that Angular handels the part of the url after the /#. Also you'll need to include the angular-route.js file to get routing working in angular.
When you're using angular routing your index.html file will just have all the boiler plate stuff that you want to include in each view and the layout for your page will go into mainView.html. index.html will need to have <div ng-view></div> somewhere in the body to tell angular where to inject mainView.html
Related
I've been testing whether routes exist using
def test_index(self):
r = self.app.get("/")
self.assertEqual(200, r.status_code, "Status code was not 'OK'.")
My template has a hyperlink to another page. Is there a way to test if this exists?
Well, if you are testing templates, every template you render is the result of a request to some route. If you render url's in a template using url_for(), then it will raise a BuildError if the url is pointing to a non existing route, and the server will return the status code 500. Therefore, you don't need to parse your templates manually for testing purposes if you just check the route instead.
Example:
from flask import Flask, render_template_string
app = Flask(__name__)
#app.route('/index')
def index():
return render_template_string("""
{{ url_for('index') }}
{{ url_for('blabla') }}
""")
def test_index(self):
r = self.app.get("/index")
self.assertEqual(200, r.status_code, "Status code was not 'OK'.")
This will result in a
routing.BuildError: Could not build url for endpoint 'blabla'. Did you mean 'static' instead? error, which makes your tests fail.
I hope this explanation is clear enough!
I have a python-flask app. And my source.py :
from flask import Flask, flash, redirect, render_template, request, session, abort
import os
from Modules.registry_bend.DockerImageReceiver import http_requester_v2_catalog, read_configurations
app = Flask(__name__)
#app.route('/v1')
def display_index():
return render_template('index.html')
if __name__ == "__main__":
# http_requester_v2_catalog("192.168.1.7", 5000)
app.secret_key = os.urandom(12)
app.run(debug=True, host='0.0.0.0', port=3150)
I run this source.py, and then open the browser and hit localhost:5000/v1.Then index.html appears. So, the challenge is, that a few seconds later I get some data, and I want to add them to index.html. How could it be possible? I have already called index.html once.
You can send the dynamic data to your HTML by sending context variables through the render template method.
flask.render_template(template_name_or_list, **context)
Renders a template from the template folder with the given context.
Parameters:
template_name_or_list – the name of the template to be rendered, or an iterable with template names the first one existing will be rendered
context – the variables that should be available in the context of the template.
Example -
return render_template('index.html', variable1=random.random(), variable2=random.random())
And in your HTML code you need to include these flask variables.
Example -
<p> {{variable1}} </p>
<p> {{variable2}} </p>
And whenever you refresh you html page in your browser. The new data will be displayed.
I am very new to Flask. I have a mysql database and a template. Let's say I have 3 images
<div><img src= pathOfImage id="profile1"/></div>
<div><img src= pathOfImage id="profile2"/></div>
<div><img src= pathOfImage id="profile3"/></div>
The id of each image (profile1,profile2,profile3) is the primary key of the some tables in the database. What I want to do is to find the values of the corresponding attributes of that tuple by using the primary key. Then, load that those values to the template from the tuples.
And, I have the following code in Python:
from flask import *
#app.route("/")
def index():
return render_template("index.html")
#app.route('/experts')
def route1():
return render_template("experts.html", data=data)
The snippet of HTML code I gave above is in expert.html. I almost of SQL query that was not listed above, data on the second parameter in render_template in route1() is the SQL tuple, which generate all these images and the ID.
I have tried to put a button next to the images, and give id to the button instead. Then, pass the id to the python script as a variable using Ajax, and get the SQL tuple.
However, this isn't the hard part. The hard part is making the new route and loading the content. I have tried make a new route using "app.route" and pass the data into the second parameter of render_template. But, it didn't redirect to a new profile, and the method was called before I even click on the profile.
previously, I used button to retrieve the id:
<html>
<body>
<button id='1'>Button1</button>
<button id='2'>Button2</button>
<button id='3'>Button3</button>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"</script>
<script>
$(document).ready(function() {
$('button').click(function(event) {
var the_id = event.target.id;
$.ajax({
url: "/get_id",
type: "get",
data: {the_id: the_id},
success: function(response) {
},
error: function(xhr) {
}
});
})});
</script>
and, I used these to generate a new template:
import flask
from flask import *
from flaskext.mysql import MySQL
#app.route("/")
def index():
return render_template("index.html")
#app.route('/experts')
def route1():
return render_template("experts.html", data=data)
#app.route('/get_id')
#app.route('/profile')
def route2():
button_id '"' + flask.request.args.get('the_id') + '"'
//some code here to get the tuples that I need "client_info" and
//"skill_info" variable below
return render_template("profile.html", client_info=client_info,
skill_info=skill_info)
Hope someone would give a fresh start. Thanks in advance!
Instead of passing info by ajax you can pass it through the route url.
experts.html
<div><img src="pathOfImage"></div>
<div><img src="pathOfImage"></div>
<div><img src="pathOfImage"></div>
flask routes
import flask
from flask import *
from flaskext.mysql import MySQL
#app.route("/")
def index():
return render_template("index.html")
#app.route('/experts')
def route1():
return render_template("experts.html", data=data)
#app.route('/profile/<id>')
def route2(id):
# id variable contains user profile id string as per user click
# depending on id set variables client_info and skill_info and render
return render_template("profile.html", client_info=client_info, skill_info=skill_info)
{% for profile in profiles %}
<img src="{{profile.img}}">
{% endfor %}
...I guess? maybe?
So I am serving a index.html file from Flask.
The index.html file comes from a built project using: https://github.com/facebookincubator/create-react-app
I have a couple routes setup in the React app, for example:
"/users"
and "/contracts"
When I refresh one of these routes, I get a 404 from flask, but while "clicking" on links found on the site, they work perfectly fine.
When you are clicking the links in the interface, React is re-rendering the page without any server-side intervention, and then updating the route in the URL bar. When loading however, you are making that route request to the server direct, and Flask does not have that route registered.
Simplest way is to register these routes in the decorator for the function serving your homepage view
#app.route('/')
#app.route('/users')
#app.route('/contracts')
def home_page():
If there are many many routes, you may want to use the catch-all URL pattern.
Specifying every route is too prone to error. Here is a more general solution.
Add an error handler to catch 404:
#app.errorhandler(404)
def handle_404(e):
if request.method == 'GET':
return redirect(f'/?request_path={quote_plus(request.path)}')
return e
The error handler will redirect to the home page, where your React works, passing the actual requested request_path as a parameter.
In your view handler do this:
#app.route('/')
def public_page_index(request_path=None):
return render_template('index.html',
request_path=request.args.get('request_path', ''))
The index.html template will create a hidden input:
<input type="hidden" name="request_path" value="{{request_path}}">
Then the actual React path will be available for your React code to respond to. This is what I've done in my Home page component, using jquery and useHistory().
useEffect(() => {
// find if server refresh needs history
const $request_path = $('input[name=request_path]');
const val = $request_path.val();
if (val) {
$request_path.val("");
history.push(val);
return;
}
}, []);
i'm always using the standard Flask-command render_template(), well, to render my templates. The whole template is just static, but there is one form, which is changing after user's input and one image-slider. Now the issue: When the user submits his/her input the wohle template gets re-rendered.
Is it possible that i just update the form-data and leave the rest of the page untouched?
My template looks like that:
<html>
<head>
</head>
<body>
<form action="/" method ="POST" id="Form">
{{msform.ms_1}} is to {{msform.ms_2}} like {{msform.ms_3}} is to {{msform.ms_submit}}
</form>
</body>
</html>
My views.py follows:
#app.route('/', methods=(['GET','POST'])
def index():
if request.method == 'POST':
msform = msForm(request.form, prefix='ms')
msform.ms_submit.label.text= msform.ms_3.data + msform.ms_2.data
return render_template(template, msform=msform)
return render_template(template, msform=msform)
Where should i place the first answer? Thanks, FFoDWindow
If you want the form to send a request with the data without reloading the whole page, then the solution is to send the form data using a XHR request (AJAX request) using JavaScript.
There's no way for the server to refresh just a portion of a template after it's been sent to the browser. HTTP is stateless, so after your browser makes the submit request, the server replies with the template you render, and that's it.
If you need to "replace" or "re-render" just a portion of the page without doing a full page reload, you need JavaScript and and XHR request.
You would need to create a Flask endpoint to receive the POSTed data.
Example using jQuery:
$("#your-form").submit(function(e) {
e.preventDefault(); // Prevent the normal form submit
$.ajax({
type: "POST",
url: '/your-api',
data: $("#your-form").serialize(),
success: function(data) {
// Do something here. For example, the server can return JSON here and you use Js to create the template client-side, or you server can return an HTML fragment and here you append it to a dom node
}
});
});
Normally, these kind of endpoints returns JSON, but if you want to stick with your server side templates as much as possible, you could return the re-rendered form as a response to the AJAX call, and then append with jQuery that response into the container element, effectively replacing the form.
Let's say you're using Jinja2 as a template engine. Then you can have a partial for the form which you normally include in the main template when you render the full page the first time.
You then can render just the same partial when you respond to the AJAX request on submit.
Hope this is helpful.