Passing a list from peewee to jinja2 in flask - python

I'm trying to write a Flask application that queries my database (using peewee), and sends the results into Jinja2 for rendering. My view looks like this:
#application.route('/maindash')
def maindash():
sq = Selfreported.select().join(Demog).where(Demog.mrn == session['mrn']).order_by(Selfreported.reportingdate)
series1data = ["Series 1", ([s.reportingdate, s.series] for s in sq)]
jsonedData = json.dumps(series1data)
return render_template('maindash.html', seriesdata=jsonedData)
To pass the results from the query into Jinja2, I know that I need to serialize the data. But when I call json.dumps: TypeError: at 0x104854be0> is not JSON serializable. So I guess I am not actually getting the data, but trying to serialize the query object itself?
Every peewee example I've looked at uses the object_list helper function from peewee-flask, rather than passing query results straight into render_template. I've looked at object_list, but I'm having a hard time understanding it --
def object_list(template_name, qr, var_name='object_list', **kwargs):
kwargs.update(
page=int(request.args.get('page', 1)),
pages=qr.count() / 20 + 1
)
kwargs[var_name] = qr.paginate(kwargs['page'])
return render_template(template_name, **kwargs)
Is there a method on a QueryResultWrapper I should be using to get the actual data rather than objects? I've looked at tuples() and dict(), but I couldn't iterate over them.

There is no reason to serialize the data before passing it to Jinja as Jinja is written in Python and can handle anything that Flask can handle. Simply pass series1data into your render_template call and walk over it in your template:
return render_template('maindash.html', seriesdata=series1data)
{# maindash.html #}
{% for reportingdate, series in seriesdata[1] %}
{{ reportingdate }} - {{ series }}<br>
{% endfor %}

Related

Django : how to use modified queryset in templates without saving modification

In my views.py, I do:
context_data = {}
all_answers = Answer.objects.all()
for i in range(0, len(all_answers)) :
all_answers[i].text = modify_text(all_answers[i].text, request)
context_data ["all_answers"] = all_answers
print(context_data ["all_answers"][0].text) #Check that it was modified
return render(request, 'template.html', context_data)
And in my templates I have like :
{% for answer in all_answers.all %}
{{ answer.text}}
{% endfor %}
The check shows that the modification is made, yet it's my template the answer.text is the unmodified data from the database.
I saw that the type of the context_data ["all_answers"] is a queryset, that I guess is triggered during the template rendering, making any unsaved changes useless, how to make my changes show in the template?
I have tried :
context_data ["all_answers"] = list(all_answers)
To load the queryset. The check works but then nothing shows in the template (1)
An error arises during the template render when I used this function to load the queryset into a list of dict.
I also saw a [linked question without answer].3
I don't want to save the changes as they are customized for each request (for each user basically).
** TLDR: How to see my modifications in the templates without saving the changes into the database ?**
PS: Using Python 3.6.8, Django 2.2.3.
Querysets are not data holders they are just lazy references, and get evaluated on runtime. The problem with your code is that you are modifying instances in queryset (which is also wrong way you should iterate using in operator like).
for answer in all_answers:
answer.text = modify_text(answer.text, request)
The real problem is that you are calling all method on queryset in your template again all_answers.all which returns a fresh queryset and without changes you made so you should, in template, do
{% for answer in all_answers %}
{{ answer.text}}
{% endfor %}
In Python you should never iterate through range(len(something)), but always over the thing itself. In the case of Django querysets this is even more important, since accessing an item in an unevaluated queryset via its index ([i]) actually causes a separate request to the database each time.
Do this instead:
for answer in all_answers:
answer.text = modify_text(answer.text, request)
context_data ["all_answers"] = all_answers
print(context_data ["all_answers"][0].text) #Check that it was modified
Note that the loop evaluates the queryset, so the [0] there doesn't cause another db request.

Is there a way to easily pass a JSON object to Django context for Chart.js?

I want to use Chart.js as the plotting tool and write a Django view that will run an ORM query, get some data, turn it into JSON, pass the JSON data to the Django context, and render the plot in the Django template without too much fuss. I am hoping to do this as simply as possible.
I was able to do something like this with Highcharts-django but it is prohibitively expensive.
This is roughly what I'd like to do:
(1) Get data loaded in 'get_context_data' via an ORM query in views.py and format the data into json using 'local_utils.py' method generate_chart(data)
from local_utils import generate_chart
class MyView(TemplateView):
template_name = "template.html"
def get_context_data(self, *args, **kwargs):
data_source = MyModel.objects.fitler(start_date__gte=start_date).values()
my_chart = generate_chart(data_source)
context['my_chart'] = my_chart
(2) Pass the data to the method generate_chart(data_source) and return a LineChartJSONView object (or something)
from random import randint
from django.views.generic import TemplateView
from chartjs.views.lines import BaseLineChartView
def generate_chart(data_source):
class LineChartJSONView(BaseLineChartView):
def get_labels(self):
"""Return labels for the x-axis."""
return data_source.values_list('x-data', flat=True)
def get_providers(self):
"""Return names of datasets."""
return ['data']
def get_data(self):
"""Return datasets to plot on y-axis."""
return data_source.values_list('y-data', flat=True)
line_chart = TemplateView.as_view(template_name='line_chart.html')
line_chart_json = LineChartJSONView.as_view()
return line_chart_json
(3) Pass the context object my_chart to template.html
<head>
{{ my_chart|load_data_to:"container" }}
</head>
<body>
{# Other stuff #}
{% if chart %}
<div id='container'>Chart will go here</div>
{% endif %}
{# Other stuff #}
</body>
(4) Plot something like this: https://github.com/peopledoc/django-chartjs#3-get-a-chartjs-line-chart
I have seen the usage in the docs where the only thing happening in a View is the plotting. However, I'd like to have the plot embedded within a TemplateView. Is this possible with Chart.js? If yes, how?

Can't pass object of model in arguments of django custom template filter

I created a custom filter in django template, but django has some constraints in passing no. of arguments, it allows only one or two arguments for custom filter functions Read more. And, i want to pass two arguments to my custom filter one is string and second one is object of model class. But can't able to successfully accomplish this.
index.html
{% load has_permission_filter %}
{% for u in users %}
<span class={{ user|has_location_perm:('user.view_user', u)}}>View</span>
{% endfor %}
In above template user is current logged user and users is a list of instances of User model class.
has_permission_filter.py
def has_location_perm(user, args):
perm_str, obj = args[0], args[1]
// business logic
if user.has_perm(perm_str) and business_logic_check(perm_str, obj):
return 'allow'
else:
return 'not-allow'
So, I want a some sort of solution which helps me in passing object in filter function from django template.
You can't use multiple arguments with filters. You can with a simple tag though.

Custom Query and Model in Django

I want to create a custom model with methods that connect to an existing DB and return data based on custom queries injected into Django. I am obviously having some problems with this, and am wondering if this is possible with my current approach. I feel like this is either a trivial question or I am misunderstanding something fundamental here. Here is my code so far:
from django.db import models
import datetime
from django.utils import timezone
class data_model(models.Field):
description = "return and create data objects for visulaizations"
def __init__(self, days, action):
self.days = days
self.action = action
if(self.action == ""):
self.action = "inspections"
getVioPoints(self.action)
def getVioPoints(self):
#get points query here and get data from db
return self
Within getVioPoints, I want to create a query string - like what you would see in a PHP $query = "select tuples where what I want = something" type of situation. Then return the data in a way that my template views can access it like so:
<ul>
{% for choice in data_returned %}
<li> {% choice.title %} </li>
{% endfor %}
</ul>
Any ideas? Any assistance would be greatly appreciated.
Thanks.
You can make custom query and put result into json.
You can read about custom queries here:https://docs.djangoproject.com/en/dev/topics/db/sql/#executing-custom-sql-directly,
but this isn`t django-way - you just ignore orm layer and have to write all sql queries by yourself, I recommend you to create model, connect it to db and make queries through orm.

How to order a set of object in a view

My code currently lists all domains in a server using:
{% for domain in server.domain_set.all %}
I want to order the domains in the view by their url. Something like:
{% for domain in server.domain_set.all().order_by('url') %}
But I get an exception "could not parse the remainder". How can I order the list?
The "could not parse the remainder" errors is because you're including Python code in your django template. Django doesn't allow that.
You could add a method on the model:
def sorted_domains(self):
return self.domain_set.all().order_by('url')
And then call it like this:
{% for domain in server.sorted_domains %}
An alternative is to set the default sort order on your Domain model with a Meta attribute.
You can use a dictsort filter:
Takes a list of dictionaries and returns that list sorted by the key
given in the argument.
{% for domain in server.domain_set.all|dictsort:'url' %}
Also see:
Sorting related items in a Django template
order_by template filter

Categories