I am planning on plotting excel data with a django site. I just mocked up a demo model, view and all that. Now I am stuck because I was hoping there was a way to process the data in my view and send the finished bar-graph (or the like) directly to the template. But I cant figure it out.
I know I can do it with js in the frontend, but I would really like to do the whole thing in python before sending it to the template. Is this bad practice? I can’t find a django app or package that does this. It there one?
My plan was to generate and plt.save() the plot to the media folder and the send the file-url along in the context, but it seems like there should be a better way somehow.
What is best practice here?
Just for info my demo model, view and template is here:
models.py:
from django.db import models
# Create your models here.
class Freetime(models.Model):
name = models.CharField(max_length=100)
days = models.IntegerField()
def __str__(self) -> str:
return self.name
view:
from django.shortcuts import render
from .models import Freetime
# Create your views here.
def index(request):
freetimes = Freetime.objects.all()
context = {"freetimes": freetimes}
return render(request, "days\index.html", context)
index.html:
<ul>
{% for f in freetimes%}
<li>{{f.name|capfirst}} has {{f.days}} left</li>
<br>
{% endfor %}
</ul>
Keep in mind that what Django is returning to the browser is an HttpResponse - an HTML document. Whatever you can do in HTML is what you can provide in your response.
Yes, there are ways to include the Base64 representation of an image in the img tag, but I’m not sure that’s really any “better”.
It means that what a view generates in terms of a page must be HTML. If you can do something in HTML, you can return it in a view. If it’s not something you can do in HTML, then it can’t be returned by a view. (Not, strictly speaking, an absolute truth - but close enough for this discussion.)
There is a bunch of different approaches you could take - and the one you took (write out an image and insert the URL to the image in the HTML template) is not bad at all imo.
A few thoughts:
You can indeed (as Ken already said) encode the image directly to Base64 and pass it as context to your template, and insert it into the template. This makes the returned HTML bigger of course and it will take slightly longer to render the page, whereas your current approaches generates a new request to the servere - which then just returns a static file.
An alternative - and not necessarily better but just to build awareness of your options, you could create a separate view that returns an image binary (PNG or JPG); and just have your <img> tag refer to that view. This can be useful in certain situations; and if the image doesn’t change very often you can put caching on that view to avoid actually generating it every time. Or you generate the image from a cron job and serve those, etc.
You said: “I know I can do it with js in the frontend”. This is actually a pretty common pattern for charts, where your app just provides the data (in whatever format) and you use a JS library to plot the chart.
An easy approach to doing this is to use a Python library that does this for you (embeds data + JS in HTML). Check out Plotly - which is free & open source and does just this. Use the Plotly Figure class to_html method (doc). For example:
def some_view(request):
fig = [... call some Plotly methods to create your figure ...]
context = {'chart': fig.to_html(full_html=False)}
return render(request, "days\index.html", context)