Sharing data between plotly dash and django views - django

I want to store some json data that returns from a django view in dcc.store on app startup. I'm new to django-plotly-dash. Is there any resources I can refer to solve this. Djnago View looks like this
def renderPage(requests):
data = load_data()
context = {}
context = {
'page_data' : data
}
return render(requests, 'dashboard.html', context)
Following is the code snippet of the layout
app.layout = html.Div(
[dcc.Location(id="url"), dcc.Store(id="page-data"), html.Div(id="page-content")],
)

Related

share dynamic object (not stored in DB) between views Django

my views.py
from django.shortcuts import render
from django.http import JsonResponse
from home_page.models import UploadNet
from home_page.forms import NetForm, ConfigForm
from backend.NetListBuilder import NetListBuilder
from backend.ConfigBuilder import ConfigBuilder
def set_configuration(request, net_file=None):
if "upload_net" in request.POST:
net_path = os.path.join("media/net_files", net_file.name)
netlist = NetListBuilder(net_path)
config = ConfigBuilder(netlist)
context = {'config': config,}
return render(request,'configuration.html', context=context,)
return render(request,'configuration.html', {'net_file': None},)
def save_config(request):
if request.is_ajax():
response_data = {}
json_data = {}
json_data = request.POST['json_data']:
response_data["result"] = "save file"
return JsonResponse(response_data)
context = {'net_file': None}
return render(request, 'rules_list.html', context=context)
I want to share netlist and config objects (without saving them in DB) in rules_list view. how can i do that? should i pass them into configuration.html file?
Django is built on the philosophy of request->process->response. Hence there cannot be shared states between views. But in case you still do want to share, then either use, DB, the browser's local storage or session available in Django.
https://docs.djangoproject.com/en/3.0/topics/http/sessions/
If you are trying to share a query output or nonserializable data, then you would have to use a cache. https://docs.djangoproject.com/en/3.0/topics/cache/
OR
IF not cache then a temporary table, where you could dump data and clear the data after you have finished using.

'list' object has no attribute 'json'

I'm trying to fetch all the products from the firebase database, but in the json data form.
Here's the structure of my database:
products{
0{
name:...
price:...
}
1{
name:..
price:..
and so on. And below is the code I tried:
import json
from .models import Product
import pyrebase
def get_products():
database = firebase_key().database()
product_list = Product.objects.all()
r = database.child("products").get().each()
jsonList = r.json()
jsonData = jsonList['products']
data = []
for products in r:
productData = {}
productData['name'] = products.name
productData['image'] = products.image
productData['price'] = products.price
productData['description'] = products.description
data.append(productData)
return data
I'm new to both django and firebase, so any help would be appreciated
As #Kevin pointed out the each does not return a json, but a list. You can check it out on the pyrebase documentation.
Your code should probably look like this:
all_products = database.child("products").get()
for product in all_products.each():
data.append(product.val()) # This works if your fields have the same names.
Edit
If you still need data as a JSON.
json_data = json.dumps(data)

Add route to view in flask-admin

so basically I'm trying to add a custom endpoint to my Flask + Flask-Admin app that allows admins to download a CSV.
Something like this:
class MyAdminIndexView(AdminIndexView):
#expose('/')
def index(self):
return self.render('admin/home.html')
def is_accessible(self):
return current_user.has_role('admin')
#expose('/csv-export')
def csv_export(self):
batch_num = request.args.get('batch_num')
if not batch_num:
flash('Invalid batch id', 'danger')
abort(404)
si = io.StringIO()
cw = csv.writer(si)
rows = MyObj.query.filter_by(batch_num=batch_num).all()
cw.writerows(rows)
output = make_response(si.getvalue())
output.headers["Content-Disposition"] = "attachment; filename=export.csv"
output.headers["Content-type"] = "text/csv"
return output
But if I add this to my base admin view, the '/csv-export' route doesn't register and I get a 404.
I guess I could add an entirely new Blueprint just for this endpoint but it seems like a lot of work for a simple endpoint that doesn't require a separate template view. Any tips?

Update Existing Document : Mongo Alchemy

I need some help with MongoAlchemy. I'm trying to create a web application with python, flask, Mongo DM and Mongo Alchemy (as an object document mapper) and I'm struggling with updating existing documents.
My problem is that I cannot update an existing document through it's object Id. Below I'm attaching my def for updating
#app.route('/update', methods =[ 'GET', 'POST' ])
def update():
if request.method == 'POST':
id = request.form['object_id'] # Getting values with html
patientzero = BloodDoonor.query.get_or_404(id)
first_name = request.form['name']# Getting values with htmlform
last_name = request.form['surname']# Getting values with html form
blood_type = request.form['blood_type']# Getting values with html
update_record = BloodDoonor.patientzero.update(BloodDoonor.last_name = last_name)
return render_template('update.html', result = result)
And flask gives me that error:
AttributeError AttributeError: type
object 'BloodDoonor' has no attribute 'patientzero'
I'm very new to Python and not very good in code. Please forgive me for the sloppy description I gave above. Any help would be appreciated.
To update an existing document just change the value of the object which you queried from db with form values and then just save that object:
#app.route('/update', methods =[ 'GET', 'POST' ])
def update():
if request.method == 'POST':
id = request.form['object_id']
patientzero = BloodDoonor.query.get_or_404(id)
patientzero.first_name = request.form['name']
patientzero.last_name = request.form['surname']
patientzero.blood_type = request.form['blood_type']
patientzero.save()
return render_template('update.html')

Dynamic FilteredSelectMultiple in django-admin

I don't know if this is even possible, any way, I currently have something as the following:
class Incidence(models.Model):
...
instalation = models.ForeignKey('Instalation')
machine = models.ManyToManyField('Machine')
...
class Machine(models.Model):
...
instalation = models.ForeignKey('Instalation')
...
So Machines belongs to instalations and incidences are related to machines and incidences, the idea is to put a dynamic FilteredSelectMultiple widget to select the machines related with the incidence in the admin page. The admin currently is something as:
class IncidenceMachineForm(forms.ModelForm):
filtered_machine = ModelMultipleChoiceField(
queryset=Machine.objects.order_by('hostname'),
required=False, widget=FilteredSelectMultiple("filtered machine name", is_stacked=False)
)
class Meta:
model = Incidence
And then, the modelAdmin uses the form IncidenceMachineForm. The idea is that when you select the instalation of the incidence, only the machines related to that instalation are available for selection. I guess something as this is not possible:
queryset=Machine.objects.filter(instalation=self.instalation).order_by('hostname'),
Any ideas will be highly appreciated. Thanks!
I notice that FilteredSelectMultiple widget has already cached, converted and changed the name of original widget after the page is loaded, so changing the "option" list of "select" tag is not enough.
I came up with this solution:
wrap "select" list inside another element ("div" for instance)
use data received from ajax call to re-create the original list
call "SelectFilter.init" to re-construct the FilteredSelectMultiple widget
Here is the code I have tested:
$('#id_instalation').change(function() {
var selected = $('#id_instalation').val();
if(selected) {
$.ajax({
url: '/url/to/get/machines/' + selected,
success: function(list) {
var options = [];
options.push('<select multiple="multiple" class="selectfilter" name="machine" id="id_machine">');
for(i in list){
options.push('<option value="' + list[i][0] + '">' +
list[i][1] + '</option>');
}
options.push('</select>');
$('#machine_wrapper').html(options.join(''));
// Change title of widget
var title = $('#id_instalation option:selected"').text().toLowerCase();
SelectFilter.init("id_machine", title, 0, "/path/to/django/media/");
},
error: function() {
alert('Server error');
},
});
}
}
This is the sample of data returned from ajax call:
[[1, "Machine 1"], [2, "Machine 2"], [3, "Machine 3"]]
For server side implementation, please see Chris Pratt's answer
Note: tested with:
jquery-1.7.2
django 1.2.5
You can do that after the model has been saved, and there's an instalation associated with it to use (though the lookup would be instalation=self.instance.instalation).
However, that doesn't do you much good, because if a different instalation is selected the list would still be the one for the old selection, and obviously you get no help when first creating the object.
As a result, the only way to accomplish this is with AJAX. You create a view to receive the selected instalation id, and return a JSON response consisting of machines associated with it. Tie the view into your urlconf, and then hit it with AJAX and update the select box based on the results.
from django.http import Http404, HttpResponse
from django.shortcuts import get_object_or_404
from django.utils import simplejson
def ajax_admin_get_machines_for_instalation(request):
instalation_id = request.GET.get('instalation_id')
if instalation_id is None:
# instalation_id wasn't provided so return all machines
machines_qs = Machine.objects.all()
else:
instalation = get_object_or_404(Instalation, pk=instalation_id)
machines_qs = Machine.objects.filter(instalation=instalation)
# 'name' is the field you want to use for the display value
machines = machines_qs.values('pk', 'name')
return HttpResponse(simplejson.dumps(machines), mimetype='application/json')
Then the JS:
(function($){
$(document).ready(function(){
function update_machine_options(){
var selected = $('#id_instalation').val();
if (selected) {
$.getJSON('/url/for/ajax/view/', {
instalation_id: selected
}, function(data, jqXHR){
var options = [];
for (k in data) {
options.append('<option value="'+data[k].pk+'">'+data[k].name+'</option>');
}
$('#id_machine').html(options.join(''));
});
}
}
update_machine_options();
$('#id_instalation').change(function(){
update_machine_options();
});
});
})(django.jQuery);
from django.contrib.admin.widgets import FilteredSelectMultiple
#admin.register(YourModel)
class YourModelAdmin(admin.ModelAdmin):
def formfield_for_manytomany(self, db_field, request, **kwargs):
kwargs['widget'] = FilteredSelectMultiple(
db_field.verbose_name,
False,
)
return super().formfield_for_manytomany(db_field, request, **kwargs)
fast and don't need to override ModelForm or etc.
effect all m2m fields.