How to render a template with dynamic CSS? - django

I want to create a dynamic CSS file in a view and then render a template which loads that CSS file. Depending on the arguments given to the view, the CSS may have different values at certain places every time the view is called. How would I go about doing that? (I should add that I have no experience with writing files in Python/Django.)
Here is a simplified example of how I think it should work:
# urls.py
urlpatterns = patterns('',
(r'^myview/(?P<color>[0-9a-f]{6})/$', create_css_file),
)
# views.py
def create_css_file(request, color):
raw = "#charset 'UTF-8';\n\n"
raw += "body {\n"
raw += " color: #" + color + ";\n"
raw += "}\n\n"
f = open('mydynamic.css', 'r+')
f.write(raw)
return render_to_response('mytemplate.html', locals())
# mytemplate.html
{% extends "base.html" %}
{% block head %}
<link rel="stylesheet" media="screen" href="{{ f.name }}" />
{% endblock %}
For some reason, that doesn't work, although in the resulting HTML page's source code, it looks like the CSS file is loaded correctly. The f even arrives at the template correctly, because I can see its contents when I change the <link>... line to
<link rel="stylesheet" media="screen" href="{{ f }}" />
(finstead of f.name). But the HTML is rendered without the desired color setting. Can anybody tell my why that is?
I suspected some path issue, and I toyed around quite a bit with different paths, but to no avail.
Please do not advise me to prepare several hardcoded CSS files (as I have found in answers to similar questions), because there will be several hundred possibilities.

If you absolutely need to you can just create a css file dynamically.
You can create an entry in your urls.py. You can name urls anything you want this could look like a static .css file to the outside world but would be created dynamically.
(r'^(?P<color>[0-9a-f]{6})/dynamic.css$', dynamic_css)
def dynamic_css(request, color):
"""
Create a css file based on a color criteria,
or any other complicated calculations necessary
"""
# do custom element positionting.
return render_to_response('dynamic.css', {'color': color})
# dynamic.css
body {
background-color: {{ color }}
}
There is no reason to write css files for this. Now you can just include
<link rel="styleshee" type="text/css" href="/purple/dymamic.css" />
In your template.
As mentioned this shouldn't be used just for changing one color. That could be done in your template. If you had to do something like this it would probably be a good idea to implement cacheing as every time a page is requested it has to dynamically generate .css that could be performance overhead. This is more of an example to show you can name urls.py entries anything you want. And include them in any way you want in html ie. if you needed a custom javascript file dynamically created you could create an entry in urls.py and then create a view that generates a .js file.

views.py:
def create_css_file(request, color):
f = color
return render_to_response('mytemplate.html', locals())
template:
<body style = "color:{{f}}!important;">
Don't create css file on the fly it is unnecessary.

I went with #CatPlusPlus's suggestion: Calculating the necessary values in a view and passing the template a very long string (raw) which contains the entire CSS. In the template, I include it like so:
<style media="screen">{{ raw|safe }}</style>
Thanks everyone for your efforts!

Related

Django - create code blocks in html templates

I would like to create a web page that will display data I have in a table inside a code block just the way it is here, even with a copy function.
I can already display the data on the page, I just like to have it formatted in a pretty box, maybe even with syntax highlights, I looked at Pygments but I can't get it to work.
Below is a sample code block that I would like to re-create in my Django app.
Please don't pay attention to the actual code, this is only a sample.
I would appreciate if you could please let me know in detail how to implement this.
# Python Program to find the area of triangle
a = 5
b = 6
c = 7
# Uncomment below to take inputs from the user
# a = float(input('Enter first side: '))
# b = float(input('Enter second side: '))
# c = float(input('Enter third side: '))
# calculate the semi-perimeter
s = (a + b + c) / 2
# calculate the area
area = (s*(s-a)*(s-b)*(s-c)) ** 0.5
print('The area of the triangle is %0.2f' %area)
Honestly, your question is more related to CSS and Javascript than Python / Django.
This took me a while...Based on what you said, I will assume you know the basics of Django.
models.py
from django.db import models
class Codeblock(models.Model):
text = models.TextField()
...
views.py
from .models import Codeblock
def codes(request):
codeblocks = Codeblock.objects.all()
return render(request, 'list_codes.html', {'codeblocks': codeblocks})
To format code blocks you can use HTML pre and code tags (Bootstrap 5 examples):
<pre><code>{{codeblocks.text}}</code></pre>
The tricky part was trying to find a way to hightlight the syntax. After a few dead ends I have found highlight.js that worked very well. It has documentation on basic usage and various themes for you to play with, you can test them using this CDN library, it is also possible to write your own theme.
There was one last problem related on how to copy the text. Although it is easy to copy text to clipboard, its not an easy task (at least for me) to have a styled button placed in the right place. To not extend myself, after a while I found this highlightjs-copy project, that not only copy the text to clipboard but has a perfect button in the right place.
With that being said, at last, here is an example:
list_codes.html
<!DOCTYPE html>
<html>
<head>
<!-- bootstrap -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.3/dist/css/bootstrap.min.css" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
<!-- highlight.js -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/base16/ashes.min.css" integrity="sha512-KX15mI6Sw0VzQyAOf4MAPS9BZ0tWXyZrGPHKSkqDmy40Jl+79f8ltpj6FvLJ+3obnH56ww0ukclsd6xGAxb5mA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
<script>hljs.highlightAll();</script>
<!-- highlightjs-copy -->
<script src="https://unpkg.com/highlightjs-copy/dist/highlightjs-copy.min.js"></script>
<link
rel="stylesheet"
href="https://unpkg.com/highlightjs-copy/dist/highlightjs-copy.min.css"
/>
<script>hljs.addPlugin(new CopyButtonPlugin());</script>
</head>
<body style="background-color: hsl(0,0%,22.5%);">
{% for codeblock in codeblocks %}
<div class="container">
<!-- Need to be in one line or will not render correctly -->
<pre><code class="language-python">{{codeblock.text}}</code></pre>
</div>
{% endfor %}
</body>
</html>

Static files being referenced via different path in same Django view

I recently updated one of my views and URLs to take an additional parameter and now that I have done this the page which is rendered displays with no css or javascript because the static path is wrong.
I am obviously not understanding correctly how static is served however I didn't think that changing the URL confs would change the path that Django would look for static. All my static for the whole site is in the one place.
urls.py
url(r'^fill/(.*)/(.*)/$', views.fill_survey, name='unique_getfile'),
url(r'^fill/(.*)', views.fill_survey, name='unique_getfile'),
and here is my view ... first block executes for the first url match and the second block executes for the bottom url
def fill_survey(request, unique_url, new_name="blank"):
"""
get file or redirect to error page
"""
if len(unique_url) < 50:
if unique_url == "new":
firstlast = new_name.split(" ")
c = Client.objects.get(firstname=firstlast[0], lastname=firstlast[1])
survey_url_number = generate_survey(request, c.email)
response = Survey.objects.get(number=survey_url_number['number'])
return render(request, 'survey/survey.html', {'survey': response})
else:
response = Survey.objects.get(number=unique_url)
return render(request, 'survey/survey.html', {'survey': response})
The rendered page then has the following static paths for the first and second url match respectively:
wwww.mysite.com/static/etc...
www.mysite.com/module_name/static/etc...
Paths in my template like:
<link rel="stylesheet" href="../../../static/classic/global/css/bootstrap.min.css">
Why are these different URLs leading to different static paths?
Thanks in advance!
Here's the relevant docs but by default Django only looks for static resources in /static/ folder or its subfolders. You can define a list of static file directories in your settings file if you want though.
https://docs.djangoproject.com/en/2.0/howto/static-files/
EDIT: Response to comment.
Can I see your template? Also, I'd try changing all your urls to end in a /$.
EDIT: Response to posted template.
I use the static tag rather than the absolute. I.E.
<link rel="stylesheet" href="{% static "/css/bootstrap-3.3.7.min.css" %}">
This way if we mess with the location of our templates we don't ned to go back and change all the templates
.
A couple thought about your html:
Since it doesn't start with / it's pointing to the a folder within the current folder.
With a / it points to the path at the root of your current web.
See https://www.w3schools.com/html/html_filepaths.asp
Regarding why I end my addresses in /$. Here's a good answer.
Why django urls end with a slash?
I wish I had a clearer answer for you but try the trailing / in the url and the leading / or {% static %} in your template.

Mako inhereting from multiple files

I have a pyramid application with multiple views each depending on a single mako template. The views are quite complicated and bug free, so I don't want to split or merge views, and by extension, the corresponding templates.
However, I would like a single view to represent all the others. Merging all the pyramid views and templates is practically not an option.
For example, I have a login view & template and a signup view & template. Now I want my root page to contain both of them. Both login and signup inherit from base.mak, which contains common scripts and style sheet imports. The following is a pictorial representation of the mako import structure I want.
base.mak
/ \
login.mak signup.mak
\ /
root.mak
Alternatively, I tried chaining them as such:
base -> login -> signup -> root
However, I think that the views no longer talk to their respective templates.
My problem comes in when I do the 3rd chain (login.mak -> signup). I'll post analogous and extract code below, since my full code is a bit long (If more code is needed, feel free to shout).
base.mak:
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>
${next.title()}
</title>
#Imports
${next.head()}
</head>
<body>
<div id = "content">
${next.body()}
</div>
</body>
</html>
login.mak:
<%inherit file="base.mak"/>
<%def name="title()">
${next.title()}
</%def>
<%def name="head()">
${next.head()}
</%def>
<div id="login">
<div id="message">
${sMessage}
</div>
<div id="form">
<form action="${url}" method="post"> <--- url returned in views.py
...
</div>
${next.body()}
signup.mak:
<%inherit file="login.mak"/>
<%def name="title()">
</%def>
<%def name="head()">
</%def>
<div id="box">
...
</div>
Now my problem here is that my url returned from my views is undefined when I try to inherit as in above.
Then of course if I get this working, adding base.mak to to inherit from signup should be trivial.
I assume that there is a simple fix for this, but I can't find an example/explanation on how to do this in pyramid, where the templates actually do stuff.
Alternatively, Is there another way to bring together multiple pyramid views and templates into a single view?
Ok, I figured it out. One has to use mako's <%include/>, and then there is no complicated inheritance structure. So, now my files look like this:
root.mak
<%inherit file="base.mak"/>
<%def name="title()">
Welcome
</%def>
<%def name="head()">
</%def>
<%include file="login.mak"/>
<%include file="signup.mak"/>
login.mak:
<%inherit file="base.mak"/>
<%def name="title()">
</%def>
<%def name="head()">
<link rel="stylesheet" type="text/css" href="${request.static_url(...
</%def>
<div id="login">
<div id=".....
</div>
and the same structure with signup.mak. base.mak still looks the same as in the question above.
Now, if you're using pyramid (I assume another framework will work the same), and you have views that receive and pass information from forms for example, then turn them into normal functions (without #view_config(renderer='path/file.mak') and place their functionality into the parent view function, in my case root. In other words:
#view_config(renderer='pyramidapp:templates/root.mak',
context=Root,
name="")
#forbidden_view_config(renderer='pyramidapp:templates/root.mak')
def root(self):
xLoginRet = login(self)
xSignupRet = signup(self)
#logic and functionality for both, return stuff to go to base.mak

How to provide canonical URL with Django HttpResponseRedirect?

This question is very similar to one I just asked href: Can I get Google search results to use/display the final redirect url?, but now the question is specific to Django.
My site has webpage urls that use the following format:
www.mysite.com/id/pretty_title
The front page links to these pages, but the href actually contains some parameters:
www.mysite.com/id/?some_ugly_parameters_to_let_me_know_what_search_it_is_from
This then redirects to
www.mysite.com/id/pretty_title
which shows the page.
My issue is that Google's search results show the link to the page as the ugly url instead of the pretty redirected one.
What I have learned is that I need to provide a canonical link. But how can I do this when the ugly url page never really exists, at least not as one that I have written?
What happens server side is that the view of the ugly url does a redirect:
return HttpResponseRedirect(pretty_url)
I think this is the correct built template tag that you're looking for.
{{ request.build_absolute_uri }}
You can just put it as part of the HTML returned from the Django template, in the <head> section.
Do you have a base.html in your Django? You can setup a {% block %} as a placeholder for the canonical URL and then set that value in each individual page that {% extends base.html %}
base.html
<html>
<head>
<link rel="canonical" href="{% block canonical_url %}{% endblock %}">
</head>
...
A lot of these proposed solutions have issues if (1) you want your www subdomain to be the canonical one and (2) there are URL params in the request path.
I would actually propose to hard code it in the base template and append request.path.
<link rel="canonical" href="https://www.example.com{{ request.path }}">
If you do end up wanting to use build_absolute_uri, I would do it as follows in your view (or you could create a template function):
canonical_url = request.build_absolute_uri(request.path)
Calling build_absolute_uri() without an argument will call request.get_full_path() and append that to your domain. If a user finds your site via https://www.example.com/?param=123, your canonical URL will include that param.

How to change a css item in a template using django admin?

I would like to know if there is some way to change a css class from a template page using django admin.
I would like to put the django tag inside of css file.
example:
body {
    background-color: {{ body.color }};
   width: {{ body.width }};
}
You could also include your CSS file using template tags. That would demand a style tag but considering the dynamic approach here it's really not much of an issue:
<html>
<head>
<style type="text/css">
{% include 'templates/mytemplate.css' %}
</style>
</head>
<body></body>
</html>
The template could then be what you described above. Then the CSS template would have access to whatever data your base template has access too.
Depending on your use case you might also do something with blocks but I'm not sure that is worth exploring at this point.
Just off the top of my head:
Create a Model to store the CSS values you want
Register the Model to show up in the Admin Screens
In your views, return these values as a dictionary
In the template, use the values as you suggested