How to manage Javascript modules in django templates? - django

Lets say we want a library of javascript-based pieces of functionality (I'm thinking jquery):
For example:
an ajax dialog
a date picker
a form validator
a sliding menu bar
an accordian thingy
There are four pieces of code for each: some Python, CSS, JS, & HTML.
What is the best way to arrange all these pieces so that:
each javascript 'module' can be neatly reused by different views
the four bits of code that make up the completed function stay together
the css/js/html parts appear in their correct places in the response
common dependencies between modules are not repeated (eg: a javascript file in common)
x--------------
It would be nice if, or is there some way to ensure that, when called from a templatetag, the templates respected the {% block %} directives. Thus one could create a single template with a block each for CSS, HTML, and JS, in a single file. Invoke that via a templatetag which is called from the template of whichever view wants it. That make any sense. Can that be done some way already? My templatetag templates seem to ignore the {% block %} directives.
x--------------
There's some very relevant gasbagging about putting such media in forms here http://docs.djangoproject.com/en/dev/topics/forms/media/ which probably apply to the form validator and date picker examples.

Been a while since I posted this problem. What I've been doing to solve it is:
write the javascript parts you need as a library which is served statically
call the routines in the static library from the template with your server side values
Restraint is required to write it in such a way that it acts as a client side script only; don't be tempted to try and inject values from the server at the time of serving the js. Ultimately I've found it less confusing to apply server side variables strictly in the html template.
In this way I'm able to:
keep the javascript selectors on html tags inside the same file (ie: the template)
avoid templatetags altogether
re-use each javascript library in different places, and
keep the css/js/html pieces in all the places where they're expected to be found
It's not perfect, but it's getting me by till a neater idea comes along.
For example a js library in "media/js/alertlib.js" might include:
function click_alert(selector, msg){
$(selector).click(function(){ alert(msg) })
}
and the template has:
<script type="text/javascript" src="media/js/alertlib.js"></script>
<script type="text/javascript">
click_alert('#clickme', {% message %})
</script>
<div id='clickme'>Click Me</div>

If more than one page uses a given JS file you should consider concatenating all of them together and minifying the result. This reduces net connects which will improve overall page load time. Don't forget to bump your expire time out to at least a week or two.

Have a look at Django Sekizai that has been created for just that purpose.

I think you are going to have a hard time keeping all four pieces together and applying them in a fell swoop - simply because some appear in your <head> tags and others in the <body> tags.
What have done is made sure that jQuery is loaded for all pages on my base.html (as well as my base css file) ... then, I have block tags for {% block css %} and {% block js %}. Templates that inherit the base.html file can supply their own javascript and css (and only the stuff that is needed).
I have created some template tags that create ajax functions whose output is based on the object being displayed (for example, including the object_id) -- which cuts down on re-coding.
One thing I haven't tried but am interested in is django-compress.

Related

Zurb foundation Interchange with Django templates?

Is Zurb Foundation's Interchange compatible for use with Django templates? I can't see a way to get them to work together, though the issue is just a technical one - Interchange seems to want html file paths, while Django's html templates render inline.
I suppose it would be possible to render the necessary templates each request into temporary files and hand those to Interchange, but that's not a very clean solution and would require a lot of boilerplate. I'm looking for a cleaner solution or for an alternative within Foundation and Django.
No, Foundation's interchange is javascript that runs in the browser within the HTML file produced by Django on your back-end. It's meant to be used for loading static files, mostly media, dependent on the size class of your browser view. E.g. inside and <img> tag:
<img data-interchange="[{% static 'images/my_background_small.png' %}, small], [{% static 'images/my_background.png' %}, medium]>
If you want to serve different HTML to different types of end-devices, you have to add that logic to your Django app's view, so that it uses a different template depending on the client. In general there are a few approaches:
What people do nowadays: Write responsive templates so that the same
HTML is served for mobile and desktop. For the few minor
differences, you can hide/show divs depending on the media class.
Check the device in your middleware and pass it as parameter to your views and templates so you can make decisions on it. Check django-mobile for example
Check the device in your server (apache or nginx) and add an HTTP header to your request that you can parse in your view (e.g. request.META.get('HTTP_MOBILE_SITE','no'). Example here

django cms [aldryn newsblog] replace template for plugin

I need to replace same plugin template on different subpages - e.g. on frontpage I need specific slider template for latest articles, in detail article I need small list, on search result without images etc.
[note: everything about aldryn newsblog app - I don't mean my own plugin!]
*(something like custom template per plugin instance)
How to replace it ? Extending template is not quite what I need - inheritance is from bottom - from lower subtemplate to base.html - but that plugin have hardcoded lower template.
Tons of IF block in template is irrational then we think in MVC.
*( like here Render Django-CMS plugins differently on different splaceholders/templates )
Or maybe just write custom template with using hardcoded including plugins ? But using django cms placeholder editor is very useful and it'll be better to keep working in that way :///
So, I create front.html base template for frontpage,
put some plugins to placeholders - and need to replace subtemplates for this plugins only in this front.html and keep subtemplates for that plugin in other places - this is main goal.
It will be the best, when django cms / aldryn newsblog provide option "custom template" per plugin instance :|
( like this one http://www.ilian.io/django-cms-plugins-with-selectable-template/ )
If I understand your question correctly (it's late here), you need a way to override plugin templates on a plugin instance basis because hacking django templates is not the way to go (I agree).
Django CMS does allow you to override plugin templates on an instance basis.
As shown in http://docs.django-cms.org/en/develop/how_to/custom_plugins.html?highlight=get_render_template#the-simplest-plugin
In your CMSPluginBase subclass add the following:
def get_render_template(self, context, instance, placeholder):
# criteria goes here
return 'sometemplate.html'
As far as how to know which template to render when (criteria), you can do a few things.
Use the page's reverse id:
page = instance.page
templates = {
'homepage': 'plugin_home.html',
'about': 'plugin_about.html',
'contact': 'plugin_contact.html',
}
return templates[plugin.page.reverse_id]
This approach has a few drawbacks:
Relies on plugin being bound to a page. (plugins can live outside of pages)
Can only work with pages that have reverse id set and reverse ids
are unique per page which means you would have to list reverse id
for every page you want to change template for.
Use a page extension to set a category per page:
Checkout http://docs.django-cms.org/en/develop/how_to/extending_page_title.html
With this approach you can then set some sort of category to multiple pages and so you can target multiple pages in one shot like so:
page = instance.page
extension = get_page_extension(page) # Check out docs for this
templates = {
'category_1': 'plugin_category_1.html',
'category_2': 'plugin_category_2.html',
'category_3': 'plugin_category_3.html',
}
return templates[extension.category.name]
Pros:
Can target multiple pages in one shot
Cons:
Relies on plugin being bound to a page.
A bit more complex
Use a template context variable:
In your templates, depending on how you're rendering your plugins, you can
provide a context variable like so:
{% with category='category_1' %}
{% placeholder 'content' %}
{% endwith %}
or
{% with category='category_1' %}
{% render_plugin yourplugin %}
{% endwith %}
Then in your get_render_template method you can access this context variable and do the following:
# Use .get() to provide fallback
category = context['category']
templates = {
'category_1': 'plugin_category_1.html',
'category_2': 'plugin_category_2.html',
'category_3': 'plugin_category_3.html',
}
return templates[category]
Pros:
No extra models.
Can target multiple pages in one shot.
Cons:
The only one I can think of is these random {% with %} in
templates.
I completely missed the newblog part, so in order to override the newsblog plugins or any plugin, just subclass the plugin class you want to override and unregister the original and then register yours, make sure yours has the same class name.
Maybe you can make the whole template logic above into a mixin to use throughout your project.
I've always wanted to give Zinnia a look, but I'm too far into working with NewsBlog on a site right now to do it (and blogs have already been posted and whatnot). You can always just add a few extra placeholders in the template (it's not the most efficient looking thing ever, but it's no load on the framework if you add a placeholder and leave it blank), that way they aren't static, and then you can put whatever plugins you want to inside of them. You can customize each component in NewsBlog pretty easily by just adding whatever you want in the structure mode. Things get trickier when it comes to having multiple blogs that act differently, but even then, as long as you're not adding components into the static placeholders provided by NewsBlog (or as I so elegantly learned it, "don't put the stuff in the blocky-things with the pins next to them), you can create different namespace for the different blogs (either in the admin, under "Configs" in the NewsBlog section, or when creating a new page and hooking it to the NewsBlog app), and you can have different templates on different blogs.
EDIT: This is a really excellent resource for touching up NewBlog without throwing the baby out with the bathwater (after three months of learning DjangoCMS, I'm still finding myself referencing it for fine-tuning pieces of NewsBlog, and to refresh my grasp on templatetags and other things that are overwhelming and have quickly left my brain along the way): https://www.django-cms.org/en/blog/2016/02/16/build-a-website-without-knowing-python-django-part-two/
*I linked to part two, as the first part deals with how to initially setup a project, and I assumed it probably wasn't relevant. Then again, if you're using Aldryn, there are some useful bits in there that can extrapolate if you're having trouble with customizing the boilerplate (or other things you'd like to configure that an Aldryn setup handles for you -- which is super awesome most of the times, but when it's not super awesome, it's usually super frustrating :)

reading and caching html fragment for use on django template

I need to grab four html fragments from an external web site and display them within my django site's header and footer. I definitely need to cache these for some period of time.
My initial thought was to use urllib2 to read the http and then write the html to files to my server. Implemented through a Django context processor, the code checks the timestamps of the four files and retrieves updated versions if necessary before reading them into template variables.
I appear to be maxing out Django's template variable size for one of the four files. This forced me to use readlines() and to pass that file into the template as an array.
Is there a more elegant way to retrieve four html fragments from an external site, cache them and pass them to my templates?
Here's what my base.html template looks like now:
{{ integration_prehead|safe }}
<head>
{{integration_head|safe }}
...
</head>
{% for l in integration_topper %}{{ l|safe }}{% endfor %}
{{ block content }}{{ endblock content }}
{{ integration_footer|safe }}
The prehead.html isn't much of anything other than the doctype and opening html tag. The head.html is a bunch of javascript and stylesheets. The topper.html and the footer.html are the biggest pieces and they're the top and bottom of the pages. The topper, in particular, can change every 15 minutes so it's not practical to hard-code it on my templates.
Topper is 39k and too big to read into a single Django template variable, hence the for loop.
If you have any control over the server you're pulling the fragments from, your best bet is to set up dedicated views that return just the fragments and not the entire HTML document.
You can then use Django views to either manually save the fragments to disk or use Django's Cache framework. The cache framework will be much more robust and provide additional means of storage such as via database or memcached, but it's not guaranteed to store the fragment for a defined period of time. For example, memcached will lose everything if the server has to be restarted.
If the source server is not in your control, I'd highly recommend that you run the document through an HTML parser first, and pull out and pass in to your template only the pieces that your need. BeautifulSoup is a nice one for python.

How to conditionally skin an existing site (for partner branding)

I've got an existing Django site, with a largish variety of templates in use. We've agreed to offer a custom-skinned version of our site for use by one of our partners, who want the visual design to harmonize with their own website. This will be on a separate URL (which we can determine), using a subset of the functionality and data from our main site.
So my question is: what's the best way to add reskin functionality to my site, without duplicating a lot of code or templates?
As I see it, there are several components which need to work together:
URL: need to have a different set of URLs which points to the partner-branded version of the site, but which can contain all the standard path info the site needs to build pages.
Template 'extends': need to have the templates extend a different base, like {% extends 'partner.html' %} instead of {% extends 'base.html' %}
View logic: need to let the views know when this is the partner-branded version, so they can change the business logic appropriately
My idea so far is to put the partner site on a subdomain, then use a middleware to parse the domain name and add 'partner' and 'partner_template' variables to the request object. Thus, I can access request.partner inside my views, to handle business logic. Then, I have to edit all my templates to look like this:
{% extends request.partner_template|default:'base.html' %}
(According to this answer, 'extends' takes a variable just like any other template tag.)
Will this work properly? Is there a better way?
If you are using different settings.py for the different sites you can
specifiy different template loading directories. (Which may default to your unskinned pages.)
Personally I'm not convinced by having different business logic in the same view code, that smells like a hack to me - the same as extensive conditional compilation does in C.
So to sum up.
Use django.contrib.sites and different settings.py
Get a clear idea, how much this is a new app/website using the same data, or just different css/templates.

How can I put a block of dynamically generated content into a django template?

I want to include things like twitter status, or delicious tags, in my django templates.
These things are dynamic, yet regular. How would this be done?
There are a number of ways to handle this, so you can choose a method that best matches your own personal style or requirements:
Template context variable: as answered by Alex you can put your content into a context variable that is included in the context of every template created by every view. Django even provides a mechanism for doing this automatically, called a context processor. Pros: very straightforward. Cons: won't dynamically refresh new content on client browsers.
AJAX dynamic loading: as mentioned by Alex and Dave you can dynamically load your content using AJAX methods. As an example using jQuery, you would put a placeholder in your template something like <div id="twitterfeed"></div> and then in a javascript block in your template put $("#twitterfeed").load("{% url twitterfeed %}"); where twitterfeed is a url so named in your urls.py. Pros: will dynamically update browsers. Cons: can be tricky if you don't know Javascript.
Inclusion tag: Django provides a type of template tag called an inclusion tag, which is basically a custom template tag that can render dynamic content. In a way it's similar to a context variable, except your code to generate the content will only be called when you use the custom template tag in your template instead of being called for every view. Another benefit is the content is generated from a template of its own. You could do this with a normal context variable of course, but it's not as clean (IMHO) as using an inclusion tag. Pros: very straightforward, clean. Cons: won't dynamically refresh new content on client browsers.
The simplest approach is to use {{ mycontent }} in your template (where you want the dynamically generated content to appear) and put the correspondence between mycontent and its value in the context you use to render the template -- i.e., the most fundamental part of django's templating.
If what you mean is that you want Ajax support whereby Javascript on the page continuously refreshes such content according to what the server wants it to be at any given time, I suggest looking into dojango, the Dojo/Django integration project -- it's not yet as fully mature as each of Dojo and Django are on their own (not version 0.4 yet), but it is already usable and useful.
A common technique is to leave a placeholder div in the generated content, then fill the div in on the client side via an AJAX call from Javascript that you include in the page.
That gives you the benefit of having a cacheable (fast loading) primary page, with separate dynamic bits. Depending on how live you want the dynamic bits, you can can even cache them for shorter durations.