Don't render whole template with Flask - python

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.

Related

Pass data from Django view to template

I have a very basic view that is supposed to render a page and pass some data to this page, here is how i do it:
def myview(request):
request = mydb.objects.filter(user=request.user)
return render(request,
"main/mytemplate.html",
context={"data":request})
When the page is loaded, the data is passed to the template, so to show that data, i'll only have to go to my html and add this:
{{data}}
But how can i do the same from a view that is not the same view that renders the page?
Let's say that this is a view that i can call with an Ajax request, so when the Ajax request is triggered, the view should send data in the same way and i want to be able to use it in the Django template language.
Here is an example:
def secondview(request):
request = mydb.objects.filter(item='free')
return HttpResponse(request)
This view is called from an Ajax request, it will send a response with the data, but i don't want to get the data in this format or in json format, instead i want to use it from the Django template language, just as i did with the first example. Is there any way to do it? Or can i only pass data to the template in the context?
1) Instead of returning HttpResponse in your secondview do this
def secondview(request):
from django.template.loader import render_to_string
x = 1
return render_to_string('template_name.jinja', locals())
2) If you want to display that response in your html, do this in your html,
<div id="x"> </div>
function someFunc(){
$.ajax({
url: "someurl",
type: 'GET',
success: function (response) {
document.getElementById("x").innerHtml = response
},
error: function (xhr, err) {
console.log(xhr.responseText);
},
cache: false,
contentType: false,
processData: false
});
I hope I've answered all of your questions, if not let me know.
def myview(request):
request = mydb.objects.filter(user=request.user)
context = {"data":request}
return render(request, "main/mytemplate.html", context)

Django: How to directly load the data from the method in the view to Html page without any request

I have a method which sends the data to HTML page direclt without any request.
views.py
def SendSentence():
sentence = "Hello World"
html = render_to_string('Display.html', Context({'Sentence': sentence}))
return HttpResponse(html)
Display.html
<html>
<head>
</head>
<body>
{% csrf_token %}
The data is ...{{ Sentence }}...
</body>
</html>
Kindly let me know Is this possible? or let me know how to get the response directly from the view.py to a html page when it is called
From docs:
A view function, or view for short, is simply a Python function that takes a Web request and returns a Web response.
request is required argument for a view function. So by definition, you cannot use SendSentence() as a view.
You can define SendSentence() as:
def SendSentence(request):
# do not do anything with request
sentence = "Hello World"
html = render_to_string('Display.html', Context({'Sentence': sentence}))
return HttpResponse(html)
However, the standard way to render a template is:
def SendSentence(request):
sentence = "Hello World"
return render(request, 'Display.html', dict(Sentence=sentence))

Pass url params from flask to angular

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

django render_to_response redirect to another view

I'm new in django
I have a render_to_response redirecting the user to the good url. But in the browser the url did not change so it's handle by the bad view...
here it is
return render_to_response('newworkflow.html/',
{'form':form,},context_instance=RequestContext(request))
Here is my urls conf:
url(r'newworkflow/$','access_mgmt.views.newworkflowform'),
url(r'newuser/$','access_mgmt.views.newuser'),
once on the newworkflow.html i have a form, which is not handle by the good view, in fact it's handle by the one where is this render_to_response.
is it possible to change the URL in the browser in the same time with a render_to_response?
I user render_to_response because on both(source and target) i activated the csrf_token
HttpResponseRedirect can be used to redirect the client to a different URL.
render_to_response "Renders a given template with a given context dictionary and returns an HttpResponse object with that rendered text."
It makes no sense to render a template into a response, if the client is going to ignore the body of the response and go to a different URL.
Instead, redirect the client to the appropriate URL, then provide the rendered response from the view associated with that URL.
Understand "The URL"
You write
is it possible to change the URL in the browser in the same time with a render_to_response?
I think you have a too-vague understanding of what "the URL" actually is.
If the browser asks for URL X, it will consider whatever you send it
to be the response for URL X, no matter what it is.
So if the server (you!) sends actual HTML content, the URL will
never change in the browser.
To make the URL change in the browser, you need to send a redirect response
(using Django's HttpResponseRedirect) to the browser.
The browser will take the URL Y contained therein
and make another request to the server with URL Y -- which is then
also shown in the browser's address bar.
The server would then send the HTML content for Y.
You cannot have both of these steps in one request: redirecting and sending content.

How can I redirect after POST in Pyramid?

I'm trying to have my form submit to a route which will validate the data then redirect back to the original route.
For example:
User loads the page website.com/post
Form POSTs the data to website.com/post-save
User gets redirected back to website.com/post
Pyramid is giving me some troubles doing this.
Here's my slimmed down views.py
def _get_link_form(post_data):
""" Returns the initialised form object """
return LinkForm(post_data)
def home_page(request):
form = _get_link_form(request.POST)
return {'form' : form}
def save_post(request):
""" form data is submitted here """"
form = _get_link_form(request.POST)
if not form.validate():
return home_page(request, form)
This is the code I've been playing around with. Not only does it not work, it also feels messy and hacked up. Surely there's a simpler way to 'redirect after-POST' in Pyramid?
Your problem is most easily solved by simply POSTing to the same URL that your form is shown at, and simply redirecting the user away from the page when the POST is successful. That way until the form is successfully submitted you do not change URLs.
If you're just dying to POST to a different URL, then you need to save the data using sessions, since you're obviously handling the form data between requests.
Typically if you want to be able to handle errors in your forms you would use a session and flash messages. To do this you simply add a location for flash messages to appear in your base template and setup session support using something like pyramid_beaker.
Assuming your home page is setup at the 'home' named-route:
from pyramid.httpexceptions import HTTPFound
def myview(request):
user = '<default user field value>'
if 'submit' in request.POST:
user = request.POST.get('user')
# validate your form data
if <form validates successfully>:
request.session.flash('Form was submitted successfully.')
url = request.route_url('home')
return HTTPFound(location=url)
return {
# globals for rendering your form
'user': user,
}
Notice how if the form fails to validate you use the same code you did to render the form originally, and only if it is successful do you redirect. This format can also handle populating the form with the values used in the submission, and default values.
You can loop through the flash messages in your template of choice using request.session.peek_flash() and request.session.pop_flash().
route_url supports mutating the query string on the generated url as well, if you want to flag your home page view to check the session data.
You can obviously just pass everything in the query string back to the home page, but that's a pretty big security vulnerability that sessions can help protect against.
The Pyramid documentation has a particularly on-point section with the following example:
from pyramid.httpexceptions import HTTPFound
def myview(request):
return HTTPFound(location='http://example.com')
I do this like so:
from pyramid.httpexceptions import HTTPCreated
response = HTTPCreated()
response.location = self.request.resource_url( newResource )
return response
This sends the HTTP Created code , 201
The Pyramid documentation has content about Redirect, you can see more information in below link :
Pyramid documentation
import pyramid.httpexceptions as exc
raise exc.HTTPFound(request.route_url("section1")) # Redirect
Edited:
Actually you can do that on client side with Javascript, first you should send particular response to client side(either with flashes some data or return Response object):
window.location = '{{ request.route_path("route_name") }}';
Assuming your homepage is the default view of your pyramid web app, you can do:
def _get_link_form(post_data):
""" Returns the initialised form object """
return LinkForm(post_data)
def home_page(request):
form = _get_link_form(request.POST)
return {'form' : form}
def save_post(request):
form = _get_link_form(request.POST)
if not form.validate():
from pyramid.httpexceptions import HTTPFound
return HTTPFound(location=request.application_url)
Basically you need to know how the home_page view was "added" to your Configurator. If your homepage actually lives at /few/levels/deep/homepage then a redirect might look like this:
return HTTPFound(location=request.application_url + '/few/levels/deep/homepage')
A clean way is using the "overload" provided by pyramid for different request types, por example, you can decorate your methods this way:
#action(request_method='GET',
renderer='mypackage:/templates/save.mako',
name='save')
def save(request):
''' Fill the template with default values or leave it blank'''
return {}
#action(request_method='POST',
renderer='mypackage:/templates/save.mako',
name='save')
def save_post(request):
""" form data is submitted here """"
# process form
In the HTML, you must call the action form, like
<form method="POST" id="tform" action="${request.route_url('home', action='save')}">
This way, one method is processed when the method POST is used, and the other when the GET is used. The same name, but two implementations.

Categories

Resources