Button with full ajax flask implementation doing absolutely nothing - javascript

I'm trying to use a custom search bar on my flask app. I didn't manage to associate it to a form (or flask-wtform) and retain its animations. Therefore I choose to implement ajax, which I'm also very interested to see working with flask.
My problem is that no matter what I do, the button does absolutely nothing!
HTML
{% block header %}
<div class="py-5 bg-image-full bgpic1">
<img class="logotipo img-fluid d-block mx-auto" src="/static/img/cerveweb_inverted.png">
<div class="searchBox">
<input id="txtBusqueda" class="searchInput" type="text" placeholder="Buscar">
<button id="btnBusqueda" class="searchButton">
<i class="fas fa-search"></i>
</button>
</div>
</div>
{% endblock %}
JavaScript
<script type="text/JavaScript">
function buscar(){
alert("2");
var texto = $("#txtBusqueda").val();
$.ajax({
url: "{{url_for('buscar')}}",
type: 'POST',
data: {'data':texto},
contentType: 'application/json;charset=UTF-8'
});
};
$("#btnBusqueda").click(function(){
console.log("1");
buscar();
});
</script>
Flask
#main.route('/buscar', methods=['GET', 'POST'])
def buscar():
# Viene de un AJAX
if request.method == "POST":
texto = request.json['data']
flash("Has buscado: {}".format(texto), "info")
return render_template('index.html')
EDIT:
Enclosing the scripts of the Jinja template, extending the functionality of a block of a base template made it work. However I'm confused about it, shouldn't scripts survive the rendering?
Also, for some reason now it is pointing out that its a bad request:
This is the current code of the script and flask:

It appears that flask has no good compatibility with Ajax, you have to switch to json to handle the Ajax request. Wich in medium to bigger sized app models with sqlalchemy is a pain. My approach was to map sqlalchemy objects directly to json counterparts using marshmallow ORM. Turning the app into a mix of classic flask-wtf and api rest.
I must clarify that I did this refactor with time as major factor, prioritizing speed over performance.
There are some pretty elegant solutions out there that don't need such mix, but I could not stop to analize them in depth. They just could not compete with the very short amount of extra lines of code I needed. (around 3 per model class, and 2 for to call it)
However, I did not manage under any circumstances to make flask respond correctly the variables to Ajax. This problem was temporarily fixed using flask session, wich works line a charm.

Related

using ajax in flask to load live logs

I am looking for some help, regarding my web server. I have a flask web server, designed to search in log files, and it does the job, but I need something else. To access the live data, to see the logs live.
It's an internal application, so the security is not a concern. The main thing it should do, is to open a file and basically simulate a "tail" command.Read the last lines, then just append the new ones, and basically that's all.
I was thinking to go with an AJAX call, but i'm not really good (at all) with JavaScript.
I was wondering about this solution :
var byteRead=0;
setInterval(function(){
$.ajax({
type: "GET",
url: "GenNumber.txt",
dataType: "text",
success: function (data) {
byteRead+= data.length;
readdata(data);
},
headers: {
"Range" : "bytes="+byteRead+"-"
}
});
},1000);
But im not quiet sure about it... neither how to adapt it (js side).
Does anyone have experience with this kind of issues or ideea how to start ?
So, in short terms in case of anyone else needs something like this, the solutin is :
#login_required
def live():
return render_template('live.html',user=current_user)
#views.route('/live_logs', methods=['GET', 'POST'])
def live_logs():
if request.method == 'GET':
def generate():
var_live = ''
var = sp.Popen(['tail','-f',var_live],stdout=sp.PIPE,stderr=sp.PIPE)
while True:
var_live_log = var.stdout.readline()
var_live_log = var_live_log.decode('utf-8')
yield "data:" + str(var_live_log) + "\n\n"
time.sleep(0.1)
return Response(generate(), mimetype= 'text/event-stream')
And the HTML file should look like this :
<head>
<meta charset="utf-8" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<br>
<hr>
<section class="section">
<div class="livelog">
<div class="columns is-centered is-mobile">
<div class="column is-dark notification is-four-fifths">
<div class="is-size-7 has-text-warning" id="display">
<ul id="display_list" class="logs"></ul>
</div>
</div>
</div>
</div>
</section>
</body>
</html>
{% endblock %}
Obviously this may differ, based on base.html
But this code will create a tail session which and stream it to the browser, also can be modified to read a file or smth..

How to execute file.py on HTML button press using Django?

My goal is to click an HTML button on my Django web page and this will execute a local python script.
I am creating a local web application as an interface to a project. This will not be hosted and will always just run on my local machine. My project is run with a python script (which carries out numerous tests specific to my project). All I need is for a button in my web interface to execute this script on my machine.
I have a template index.html where the whole web page is located. I presume I need to call some form of views function possibly when the button is pressed?
How to execute python code by django html button?
This question suggests:
def index(request):
if request.method == 'GET':
return render(request, 'yourapp/index.html', {'output': ''})
elif request.method == 'POST':
py_obj = mycode.test_code(10)
return render(request, 'yourapp/output.html', {'output': py_obj.a})
I tried this just as a test but nothing happened when I went to the URL (located in the appropriate views.py):
def runtest(request):
print("Hello World")
Popen(['gnome-terminal', '-e', 'echo "Hello World"'], stdout=PIPE)
return
However I don't quite understand if this achieves what I need it to, I am struggling to understand what the answer is suggesting.
Where in the Django framework can I specify a call to a local python script when a button is pressed?
(I have very limited experience with web applications, this is simply just meant to be a simple interface with some buttons to run tests)
You want to try to submit a form on the button click. You can then import the functions you want to run from the script and call them in your view. You then redirect to the same page.
I hope this helps!
index.html
<form method="post">
{% csrf_token %}
<button type="submit" name="run_script">Run script</button>
</form>
views.py
if request.method == 'POST' and 'run_script' in request.POST:
# import function to run
from path_to_script import function_to_run
# call function
function_to_run()
# return user to required page
return HttpResponseRedirect(reverse(app_name:view_name))
Adding to answer above. You can run the function in a different view completely:
<form method="post" action="{% url 'app:view/function' %}">
{% csrf_token %}
<button class="btn btn-danger btn-block btn-round">Perform task</button>
</form>
And render whatever template you want (same template will execute task but seem like nothing has happened). This is handy if you already have a 'POST' form handler.

Django; How can I connect javascript to db?

I'm doing project using Django and now I am trying to adapt js into the project. I'm not familiar with js and I'm wondering how I can manipulate db using js. For example, I want to use js for creating delete function. Currently, when I push delete button, I jump into the other page and then I have to push delete button again. But what I want to do is push the delete button and then pop up the window to confirm and delete something. How can I adapt js into Django in general?
Here is current way
first I have to push the button and jump into another page
<button style="display: inline;" onclick="window.location='{% url 'blog:delete_entry' entry_id=entry.id %}'" class="btn btn-link">Delete</button>
and then I have to push a button on the other page again.
<button type="submit" class="btn btn-outline-danger" id="delete-button">Delete</button>
Here is views.py
def delete_entry(request, entry_id):
entry = Entry.objects.get(id=entry_id)
if request.method != 'POST':
form = EditEntryForm(instance=entry)
else:
form = EditEntryForm(instance=entry)
entry.delete()
return HttpResponseRedirect(reverse_lazy ('blog:my_entry'))
return render(request, 'blog/delete_entry.html', {'entry': entry, 'form': form})
Anyone who can give me tips?
I could be wrong, but I typically only use javascript for the front-end. You are doing the back-end in Python with the Django frame work... it would be foolish not to use Python to manipulate the DB. Here is a template for mysql although I used Flask...
https://github.com/rootVIII/flask_mysql_template/blob/master/template.py
Even though it's Flask and not Django, the idea is still the same.
Your button should (or any form button) should have a Django endpoint associated with it (basically a path to the Django function). That way when the button is pressed, the Django/Python code on the back-end is ran. There you can perform your logic and database business in the Python code on the back-end.
Sorry for the Flask examples... but here is an endpoint for Flask in the index.html file from the above link... notice how the form action is associated with an endpoint /login_register
/login_register is what is ran when the form input button is pressed. It is a function on the back-end... in your case it might be named delete_entry
<form action = /login_register method="POST" id="userform">
<fieldset>
<!-- some labels and input values here -->
<input type="submit" name="submit" value="login/register" id="submit"/><br>
</fieldset>
</form>
So basically what I'm saying is that your button should not call Javascript. It should call a Python function on the back-end. And no you do not need to make a whole rest API to do this as was mentioned above

express.js how to update UI without refresh all page using handlebars

It's one of the first time that I use express.js and Handlebars.
I need to autocomplete this field: <input type="text" id="myInput" autocomplete="on" placeholder="Search here...">. When everyone digit to this text, I need to make a POST and after a GET without refreshing the content in the page. The problem is, when I do the GET, Handlebars refresh all page. This is the command that I use:
res.render('home',{ items:typeOfCategory});
and this is the structure of the hbs:
{{#if items}}
<ul>
{{#each items}}
<li>{{this.title}}</li>
{{/each}}
</ul>
{{/if}}
My question is: how to avoid the refreshing of the all page?
Thanks
I had read something like that in another question. Based on this tutorial: I found the answer to all my problems.
this tutorial explain how to use a PJAX library that manages both the client and server side.
Thanks to 3 rows of code you can obtain a speed navigation without reload the page.
Install client side library from jQuery-pjax page
into your html page that send the request add: <a href='/yourLink' data-pjax='main'>YourLink</a>
where main is the div that will content yout change. In my case is:
<div id="main" class="main">
{{{body}}}
</div>
In your.js file add $('a[data-pjax]').pjax(); This command 'simply call the pjax extension on every element that contains the data attribute ‘data-pjax’'
Install inside express the depency with the command: npm install --save express-pjax
Set your server:
var app = express();
var pjax = require('express-pjax');
...
app.use(pjax())
Replace the normal rendering:
res.render('index', {title: "Index"});
with
res.renderPjax('index', {title: "Index"});
UPDATE
Alternatively you can obtain the same result. Consider that the structure of the project is as follows:
views
|-> partials
| |-> addtest.hbs
|
|-> index.hbs
For example, image that in your index.hbs you have a sidebar with different items, described in this way:
<li>
<a href="#testDB" data-toggle="collapse" aria-expanded="false" class="dropdown-toggle">
<img src="../img/database-data.svg" class="svg icon">Test</a>
<ul class="collapse list-unstyled select-specific" id="testDB">
<li value="addTest" class=" ">
Add Test
</li>
....
....
</ul>
</li>
Inside the partials directory you have a simply form.
Now for manage the form you have to do two operations:
Server side: For switching from one partial to another without refresh the page, you specify:
router.get('/addtest', function (req, res) {
res.status(200);
res.header("Content-Type", "text/html");
res.render('partials/addtest', {title: "Add Test"});
});
Client side: In your client side file, you add make a simple get request:
$('#add-new-test').click(function (event) {
$.get('/addtest').then(function (data) {
$('#main').html(data);
});
});
In this way, when you make a get request with the same address (i.e in this case /addtest) the client add a part of code inside your view without refresh all.
NOTE: Keep in mind that, if you needed a some file.js in your partial, for load the file, use this:
<script>
var url = "/scripts/script.js";
$.getScript(url);
</script>
This is used for avoid: “Synchronous XMLHttpRequest on the main thread is deprecated…” because the call is asynchronous. For more info..
The problem here is that you're making the browser request a new resource each time. This is triggering your templating and serving up a brand new page every time.
You'll want to make an express endpoint which returns JSON, and then send up a request to that endpoint using something like AJAX (found in jQuery) or a similar library. This way you can make a call up to your web server, express can return you some data in a JSON format (res.json({}) and your frontend can then interpret that response and decide how to display it on the DOM.
This sort of partial updating is where you start to need frontend JS along side programatic endpoints that return JSON. This is often where some of these big frontend frameworks like Vuejs and Angular thrive, but if you're new to this sort of thing I'd recommend using jQuery to make a HTTP call to your server and return the JSON down to the frontend.

Creating confirmation dialog pages when Javascript is disabled

I'm using Django and I want my users to confirm that they really want something to be deleted. I'm considering pure Django solution (no Javascript confirmations).
According to what I think,I can create a new page containing "Yes" and "No" buttons. If user presses "Yes", my site will go on and delete the object from the database.
Is it the right way to do deletion without using Javascript? How would you implement the feature if you were me?
I would use Django's built in DeleteView, which will display a confirmation page for an HTTP GET request and perform deletion for an HTTP POST request.
The documentation gives this example:
from django.views.generic.edit import DeleteView
from django.core.urlresolvers import reverse_lazy
from myapp.models import Author
class AuthorDelete(DeleteView):
model = Author
success_url = reverse_lazy('author-list')
I'd recommend reading the documentation for the SingleObjectMixin which explains how to customise the way the view finds the object to delete (the default is to look for an URL keyword argument called pk), and for the TemplateResponseMixin which explains how to customise the template that is used (the default is 'myapp/author_check_delete.html').
This is just one of a number of class-based generic views that make basic operations (displaying a page for a single model instance, for a list of model instances, and handling editing, deletion etc.) very quick and easy to implement.
If you wanted to enhance this with JavaScript later you could always write some unobtrusive JS that detects links to the deletion confirmation page (by looking for a class, or a particular URL) and adds a click handler that pops up a confirmation dialog and then sends a POST request to the URL in the link's href attribute. You would also need to modify the view slightly to return a JSON object when request.is_ajax() is True, so that your JS would know if the deletion had succeeded or failed, which would probably involve overriding one of the methods inherited from the DeletionMixin.
That sounds fine. What I have done a couple of times is to create a confirmation template that can be used anywhere in the application:
{% extends 'base.html' %}
{% block content %}
<div class="confirmation-box">
<p>{{ message }}</p>
<div>
Cancel
<form action="{{ action_link }}" method="post">
<input type="hidden" name="next" value="{{ prev_link }}" />
<input type="submit" value="Send" />
</form>
</div>
</div>
{% endblock %}
You pass to it:
A confirmation message for the user (message)
The url to the page you are in (prev_link)
The url that should be called to perform the action (action_link)
If the user cancels the action, then she/he goes back to the original page.
If the user confirms, then the prev_link is passed as a hidden parameter, so the view can redirect the user to the original page after performing the action (although this is completely optional of course).
Which is pretty much what you propossed in your question.

Categories