Flask - possible to request most current context during subroutine? - javascript

currently I have a generator function that is called by a charting program in the javascript side of my webapp.
I am using the #stream_with_context decorator but that unfortunately only gives me the context when the generator begins running but I want the context constantly updated as I have a boolean variable that the generator needs to know that is constantly changing and I am updating it in the session dictionary.
I would like to be able to access this updated session in the generator. Or if there is any way I can communicate a boolean variable to the generator that would be fine too.
I don't care how it gets there I just thought using session would be the easiest.
Status Update: I have still not found a way to do this... It seems pretty simple but there is nothing on the internet about requesting the current context.
Flask
#app.route('/plotter', methods=['GET', 'POST'])
def plotter():
#some setup in here
#stream_with_context
def generate_data():
while True:
if(session['bool']):
#do something
#app.route('/elsewhere')
def bool_status():
session['bool'] = #new_val <---- this where the val is updated... in another view called by a button.
Javascript
// this how the generator is called
const source = new EventSource("{{url_for(source)}}");

Related

how to redirect url in flask depending on a variable

I want to redirect the URL when the variable search_done is true, but until then I want the loading file to show but i can't manage to do so.
I've tried doing all sorts of variable passing to html but because the variable changes during the run of the loading file the variable won't be true.
The URL changes to the loading file when a search button is clicked.
#app.route("/", methods=['GET','POST'])
def index():
global search_done
global songs
if request.method == 'POST':
search_request = request.form.getlist('search[]')
songs=[]
data=search_api(search_request)
search_done=False
if data!=None:
for hit in data:
songs.append(Song(hit['result']['full_title'],hit['result']['primary_artist']['name'],hit['result']['url'],hit['result']['song_art_image_thumbnail_url']))
for i in songs:
print(i)
search_done=True
return render_template('layout.html')
#app.route("/result")
def result():
global songs
return render_template("result.html",songs=songs)
#app.route("/loading")
def load():
global search_done
while not search_done:
return render_template("loading.html")
return redirect(url_for('result'))
I want the url to redirect to 'result' but it just stays as the loading page
It's not possible to do this in the way you're thinking. In short, the most simple way to get there is by adding some Javascript to the page (ajax), and poll your server to find when the variable changes. There are a few things to consider:
How will you store the variable? Session is an option for non-important, small values. Otherwise a DB may be necessary for large data sets, or a background worker may be necessary for long running processes.
Getting the value back into the view can be done using ajax (e.g. jquery $.get) and a setTimeout function with javascript. This should call a new route in your app that retrieves the value from the storage method you're using.
Going fully async and looking at Sockets (for example) will give you the ability to create more 'live' views, where your app view can listen for events and update without reloading. This does change how your app is run however.
Hope this helps!

How to get the current record in JavaScript in Odoo 10?

Does anyone know how to obtain the current record in a Python method which is called from JavaScript code?
Let's put an example:
I have my Python method:
#api.multi
def my_method(self):
_logger.info(self)
To call that method from my JS code, I have to do the following:
var MyModel = new Model('my.model');
MyModel.call(
'my_method', [current_id],
)
And because of this I need to get the current ID from JavaScript. So, before calling the method, I store the current ID in a JS variable this way:
var current_id = this.field_manager.datarecord.id
It works OK. But only when the record has already an ID. If the current record is currently being created, this.field_manager.datarecord.id returns null, and the method call fails.
What I would like is to know how to call that method even when the record has not an ID yet. For example, onchange decorator allows you to work in Python with records with are not stored in the database and therefore have not an ID yet.
Any ideas?
I don't know if this will help you but you can not
call a mehtod in api.multi withou being saved first
but you can work arround it use api.model instead
and in the funcition call just pass the id of the record
in the parametre.
MyModel.call(
'my_method', {'current_rec': current_id})
In you python handle the create mode
#api.model
def my_method(self, current_rec=None):
if not current_rec:
# in create mode
# if you need a field from the view you need to pass its value in params like the id
# because self is a dummy record that is empty not like in onchange event
# because odoo build that dummy record for you from the values that they
# are in the current view.
else:
rec = self.browser(current_rec)
# remember value in api.multi or in rec are retrieved from the database
# not the current view values so if you relay on a value from the view
# pass it in params or find a way to tell odoo to build a dummy record like in onchange.
return result
The problem here self is empty (in create mode) not like
in onchange method.
but you can always pass extra params that you can get from the current view and pass them to the method
If they are needed in your logic.
And don't forget if you are using a field in your logic, in api.multi you are using values
retrieved from the database not the values that they are in the current view (in edit mode).

How to pass data between Django module/app functions without using database in asynchronous web service

I've got a web service under development that uses Django and Django Channels to send data across websockets to a remote application. The arrangement is asynchronous and I pass information between the 2 by sending JSON formatted commands across websockets and then receive replies back on the same websocket.
The problem I'm having is figuring out how to get the replies back to a Javascript call from a Django template that invokes a Python function to initiate the JSON websocket question. Since the command question & data reply happen in different Django areas and the originating Javascript/Python functions call does not have a blocking statement, the Q&A are basically disconnected and I can't figure out how to get the results back to the browser.
Right now, my idea is to use Django global variables or store the results in the Django models. I can get either to work, but I beleive the Django global variables would not scale beyond multiple workers from runserver or if the system was eventually spread across multiple servers.
But since the reply data is for different purposes (for example, list of users waiting in a remote lobby, current debugging levels in remote system, etc), the database option seems unworkable because the reply data is varying structure. That, plus the replies are temporal and don't need to be permanently stored in the database.
Here's some code showing the flow. I'm open to different implementation recommendations or a direct answer to the question of how to share information between the 2 Django functions.
In the template, for testing, I just have a button defined like this:
<button id="request_lobby">Request Lobby</button>
With a Javascript function. This function is incomplete as I've yet to do anything about the response (because I can't figure out how to connect it):
$("#request_lobby").click(function(){
$.ajax({
type: "POST",
url: "{% url 'test_panel_function' %}",
data: { csrfmiddlewaretoken: '{{ csrf_token }}', button:"request_lobby" },
success: function(response){
}
});
});
This is the Django/Python function in views.py . The return channel for the remote application is pre-stored in the database as srv.server_channel when the websocket is initially connected (not shown):
#login_required
def test_panel_function(request):
button = request.POST.get('button', '')
if button == "request_lobby" :
srv = Server.objects.get(server_key="1234567890")
json_res = []
json_res.append({"COMMAND": "REQUESTLOBBY"})
message = ({
"text": json.dumps(json_res)
})
Channel(srv.server_channel).send(message)
return HttpResponse(button)
Later, the remote application sends the reply back on the websocket and it's received by a Django Channels demultiplexer in routing.py :
class RemoteDemultiplexer(WebsocketDemultiplexer):
mapping = {
"gLOBBY" : "gLOBBY.receive",
}
http_user = True
slight_ordering = True
channel_routing = [
route_class(RemoteDemultiplexer, path=r"^/server/(?P<server_key>[a-zA-Z0-9]+)$"),
route("gLOBBY.receive" , command_LOBBY),
]
And the consumer.py :
#channel_session
def command_LOBBY(message):
skey = message.channel_session["server_key"]
for x in range(int(message.content['LOBBY'])):
logger.info("USERNAME: " + message.content[str(x)]["USERNAME"])
logger.info("LOBBY_ID: " + message.content[str(x)]["LOBBY_ID"])
logger.info("OWNER_ID: " + message.content[str(x)]["IPADDRESS"])
logger.info("DATETIME: " + message.content[str(x)]["DATETIME"])
So I need to figure out how to get the reply data in command_LOBBY to the Javascript/Python function call in test_panel_function
Current ideas, both of which seem bad and why I think I need to ask this question for SO:
1) Use Django global variables:
Define in globals.py:
global_async_result = {}
And include in all relevant Django modules:
from test.globals import global_async_result
In order to make this work, when I originate the initial command in test_panel_function to send to the remote application (the REQUESTLOBBY), I'll include a randomized key in the JSON message which would be round-tripped back to command_LOBBY and then global_async_result dictionary would be indexed with the randomized key.
In test_panel_function , I would wait in a loop checking a flag for the results to be ready in global_async_result and then retrieve them from the randomized key and delete the entry in global_async_result.
Then the reply can be given back to the Javascript in the Django template.
That all makes sense to me, but uses global variables (bad), and seems that it wouldn't scale as the web service is spread across servers.
2) Store replies in Django mySQL model.py table
I could create a table in models.py to hold the replies temporarily. Since Django doesn't allow for dynamic or temporary table creations on the fly, this would have to be a pre-defined table.
Also, because the websocket replies would be different formats for different questions, I could not know in advance all the fields ever needed and even if so, most fields would not be used for differing replies.
My workable idea here is to create the reply tables using a field for the randomized key (which is still routed back round-trip through the websocket) and another large field to just store the JSON reply entirely.
Then in test_panel_function which is blocking in a loop waiting for the results, pull the JSON from the table, delete the row, and decode. Then the reply can be given back to the Javascript in the Django template.
3) Use Django signals
Django has a signals capability, but the response function doesn't seem to be able to be embedded (like inside test_panel_function) and there seems to be no wait() function available for an arbitrary function to just wait for the signal. If this were available, it would be very helpful

Send data to Flask server using websockets

I have a complicated project (not my code...) where a Flask servers launches computations using SCOOP -- that is, in another thread.
I'd like to know how I can send intermediary data from my SCOOP thread to display it on my Flask web page. I am not afraid of a little Javascript.
Python websockets seems like the way to go, but I'm unsure how to use it.
Let's say I will use Javascript this way in my Flask web page to fetch my data (example from Websockets' doc) :
var ws = new WebSocket("ws://127.0.0.1:5678/");
var messages = document.createElement('ul');
ws.onmessage = function (event) {
// Do stuff
}
Now, all my data is encapsulated in an object (Calibration2 -- again, not my code!). So, the following example (still from Websockets' doc) does not suit me:
#asyncio.coroutine
def time(websocket, path):
while True:
now = datetime.datetime.utcnow().isoformat() + 'Z'
yield from websocket.send(now)
yield from asyncio.sleep(random.random() * 3)
start_server = websockets.serve(time, '127.0.0.1', 5678)
Because I want the handler coroutine to be part of my Calibration2 class, and call it whenever Calibration2 wants to. But according to Websockets, the coroutine has to have this prototype, with websocket and path. But how can I access Calibration2's insides from such a function?
I'm pretty sure my issue is mostly a misunderstanding of Python scopes. I'm not a pro (yet!). So, if you can point me in some direction, I'd be glad, thanks!

Using an object property as a function and as an object simultaneously

I was wondering if there is a way to declare an object property as a function, but also as an object, at the same time.
I have a JavaScript program that provides a simple API that sends AJAX requests to a server. My goal is trying to make this API as simple and human-readable as possible.
Basically, I'd like to make it possible to do this:
var app = new App();
app.get.client(123) // Get client ID 123
app.get.client.list() // Get an array of all clients
app.login('username', 'password') // Send credentials to log as username/password
app.login.as('John') // Login using credentials stored in a server-side constant
I doubt that's even possible as I've never anything like it, but I can't think of a more clear and human-readable way to lay out methods. Sure would be nice!
A function’s an object too!
app.get.client = function(id) {
// Get client by ID
};
app.get.client.list = function() {
// List them
};
works as you’d expect.
Personally, though, I’d find:
app.clients.byId(123)
app.clients
app.login('username', 'password')
app.loginAs('John')
more readable.

Categories

Resources