I am updating old django code from method-based views to class-based views.
I know how to include media (css/js) in forms via the Media class
How can I use the media class if my class based view does not contain any forms?
CSS/JS are usually managed in the template itself and not in the view. See https://docs.djangoproject.com/en/1.10/howto/static-files/
For example, use base.html:
<!DOCTYPE html>
<html>
<head>
<title>
{% block page_title %}{{ page_title }}{% endblock %}
</title>
{% block css %}
{% endblock %}
</head>
<body>
{% block main %}
{% endblock %}
{% block scripts %}
{% endblock %}
</body>
</html>
and extend it with my_page.html:
{% extends "base.html" %}
{% load staticfiles %}
{% block page_title %}
Hello!
{% endblock %}
{% block css %}
<link href="{% static "page.css" %}" rel="stylesheet"/>
{% endblock %}
{% block main %}
Yo!
{% endblock %}
{% block scripts %}
<script src="{% static 'my_scripts.js' %}"></script>
{% endblock %}
Django Sekizai is meant for this:
Here is the example from their documentation:
{% load sekizai_tags %}
<html>
<head>
{% render_block "css" %}
</head>
<body>
Your content comes here.
Maybe you want to throw in some css:
{% addtoblock "css" %}
<link href="/media/css/stylesheet.css" media="screen" rel="stylesheet" type="text/css" />
{% endaddtoblock %}
Some more content here.
{% addtoblock "js" %}
<script type="text/javascript">
alert("Hello django-sekizai");
</script>
{% endaddtoblock %}
And even more content.
{% render_block "js" %}
</body>
</html>
This example shows everything in one template, but - of course - you can split that into multiple templates either by inheritance or includes and use the addtoblock directives in any of the partial templates.
A more complex, real life example is also in their documentation.
Here is a small mixin class that can help you add Media to views based on CreateView, UpdateView, and DeleteView:
class InjectFormMediaMixin(object):
def get_form_class(self):
form_class = super(InjectFormMediaMixin, self).get_form_class()
if hasattr(self, 'Media') and not hasattr(form_class, 'Media'):
form_class.Media = self.Media
return form_class
Example:
class CreateFooView(InjectFormMediaMixin, CreateView):
model = models.Foo
fields = (
'name',
)
class Media:
css = {
'all': ('pretty.css',)
}
js = ('animations.js', 'actions.js')
Related
I am updating old django code from method-based views to class-based views.
I know how to include media (css/js) in forms via the Media class
How can I use the media class if my class based view does not contain any forms?
CSS/JS are usually managed in the template itself and not in the view. See https://docs.djangoproject.com/en/1.10/howto/static-files/
For example, use base.html:
<!DOCTYPE html>
<html>
<head>
<title>
{% block page_title %}{{ page_title }}{% endblock %}
</title>
{% block css %}
{% endblock %}
</head>
<body>
{% block main %}
{% endblock %}
{% block scripts %}
{% endblock %}
</body>
</html>
and extend it with my_page.html:
{% extends "base.html" %}
{% load staticfiles %}
{% block page_title %}
Hello!
{% endblock %}
{% block css %}
<link href="{% static "page.css" %}" rel="stylesheet"/>
{% endblock %}
{% block main %}
Yo!
{% endblock %}
{% block scripts %}
<script src="{% static 'my_scripts.js' %}"></script>
{% endblock %}
Django Sekizai is meant for this:
Here is the example from their documentation:
{% load sekizai_tags %}
<html>
<head>
{% render_block "css" %}
</head>
<body>
Your content comes here.
Maybe you want to throw in some css:
{% addtoblock "css" %}
<link href="/media/css/stylesheet.css" media="screen" rel="stylesheet" type="text/css" />
{% endaddtoblock %}
Some more content here.
{% addtoblock "js" %}
<script type="text/javascript">
alert("Hello django-sekizai");
</script>
{% endaddtoblock %}
And even more content.
{% render_block "js" %}
</body>
</html>
This example shows everything in one template, but - of course - you can split that into multiple templates either by inheritance or includes and use the addtoblock directives in any of the partial templates.
A more complex, real life example is also in their documentation.
Here is a small mixin class that can help you add Media to views based on CreateView, UpdateView, and DeleteView:
class InjectFormMediaMixin(object):
def get_form_class(self):
form_class = super(InjectFormMediaMixin, self).get_form_class()
if hasattr(self, 'Media') and not hasattr(form_class, 'Media'):
form_class.Media = self.Media
return form_class
Example:
class CreateFooView(InjectFormMediaMixin, CreateView):
model = models.Foo
fields = (
'name',
)
class Media:
css = {
'all': ('pretty.css',)
}
js = ('animations.js', 'actions.js')
I found this project https://github.com/chhantyal/taggit-selectize and it seems to do what I want, but the example app is incomplete, so I don't know how to use it. What I basically want is that users will be able to write their own tags for a post, and that if they are typing one that has been used before by someone else, it will show up in autocomplete. I also want a search function that will use the autocomplete in the same manner. I'm sure it's not very complicated but the readme only explains how to install and what some things mean, and I was looking for a very minimal working example that makes the autocomplete work.
Thanks in advance.
I have a very specific use case. I hope my example does not over-complicate things (I add extra fields to my Taggit model). Please be aware you may need to load css and js in your html, as per this issue. I am using Django Crispy Forms.
In my app settings:
TAGGIT_TAGS_FROM_STRING = "taggit_selectize.utils.parse_tags"
TAGGIT_STRING_FROM_TAGS = "taggit_selectize.utils.join_tags"
TAGGIT_SELECTIZE_THROUGH = "jobsboard.models.SkillTags"
TAGGIT_CASE_INSENSITIVE = True
TAGGIT_SELECTIZE = {
"MINIMUM_QUERY_LENGTH": 2,
"RECOMMENDATION_LIMIT": 10,
"CSS_FILENAMES": ("taggit_selectize/css/selectize.django.css",),
"JS_FILENAMES": ("taggit_selectize/js/selectize.js",),
"DIACRITICS": True,
"CREATE": False,
"PERSIST": True,
"OPEN_ON_FOCUS": True,
"HIDE_SELECTED": True,
"CLOSE_AFTER_SELECT": False,
"LOAD_THROTTLE": 300,
"PRELOAD": False,
"ADD_PRECEDENCE": False,
"SELECT_ON_TAB": False,
"REMOVE_BUTTON": True,
"RESTORE_ON_BACKSPACE": False,
"DRAG_DROP": False,
"DELIMITER": ",",
}
In my jobsboard/models.py:
from taggit.models import TagBase, GenericTaggedItemBase
from taggit_selectize.managers import TaggableManager
class SkillTags(TagBase):
LANGUAGE = "la"
STATISTICS = "st"
CODING = "co"
DISCIPLINE = "di"
TYPES = (
(LANGUAGE, "language"),
(STATISTICS, "statistics"),
(CODING, "coding"),
(DISCIPLINE, "discipline"),
)
type = models.CharField(choices=TYPES, default=DISCIPLINE, max_length=2)
creator = models.ForeignKey(User, null=True)
class TaggedModel(GenericTaggedItemBase):
tag = models.ForeignKey(SkillTags, related_name="%(app_label)s_%(class)s_items")
class Job(TimeStampedModel):
tags = TaggableManager(_("skillset required"), blank=True, through=TaggedModel)
In my urls:
url(r'^hirer/new/$', NewJobView.as_view(), name='hirer_new_job')
In my jobsboard/views.py:
class NewJobView(FormView):
template_name = 'jobsboard/new_edit_job.html'
form_class = NewAndEditJobForm
In my jobsboard/forms.py:
class NewAndEditJobForm(ModelForm):
class Meta:
model = Job
fields = ('tags',)
For my jobsboard/templates/jobsboard/new_edit_job.html:
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block content %}
{{ block.super }}
{% crispy form %}
{% endblock content %}
for my templates/base.html:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
{% block css %}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<!-- Your stuff: Third-party CSS libraries go here -->
{% endblock %}
{% block extrahead %}
{% endblock %}
</head>
<body>
{% block content %}
{% endblock content %}
{% block javascript %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
{% endblock javascript %}
</body>
</html>
I shall try and give an example as lean as possible:
app/models.py:
from django.db import models
from taggit_selectize.managers import TaggableManager
class Post(models.Model):
name = models.CharField(max_length=100)
tags = TaggableManager()
app/views.py:
from app.models import Post
from django.views.generic import UpdateView
class PostEdit(UpdateView):
model = Post
fields = ['name', 'tags' ]
success_url = '/'
app/templates/app/post_form.html:
{% extends 'base.html' %}
{% load static %}
{% block content %}
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Speichern">
</form>
{% endblock %}
{% block css %}
{{ block.super }}
<link href="{% static "taggit_selectize/css/selectize.django.css" %}" type="text/css" media="all" rel="stylesheet"/>
{% endblock %}
{% block javascript %}
{{ block.super }}
<script src="{% static "taggit_selectize/js/selectize.js" %}"></script>
{% endblock %}
and a templates/base.html:
{% load static %}<!DOCTYPE html>
<html lang="en">
<head>
<script src="{% static 'vendor/js/jquery-3.3.1.min.js' %}"></script>
<!-- IMPORTANT: get jquery loaded ASAP. if you load it too late you get JS errors from the taggit-selectize. -->
{% block css %}
{% endblock %}
</head>
<body>
{% block content %}
{% endblock %}
{% block javascript %}
{% endblock %}
</body>
</html>
Important Note: I was having the same problems up until the point where I moved the jquery-loading up into the header.
views.py
def base(request):
return render(request,"base.html",{'':''})
def index(request):
return render(request,"index.html",{'':''})
base.html
<html>
<head>ppppppppp</head>
<body>
<h1>this is base template</h1>
</body>
</html>
index.html
{% extends "base.html" %}
{% block content %}
<body>
<h1>
Welcome to my app
</h1>
</body>`
{% endblock content %}
Here the issue is django is not at all recognising index.html only displaying extended template.
The correct flow here is to create really :) base template:
base.html
<html>
<head>ppppppppp</head>
<body>
{% block content %} {% endblock %}
</body>
</html>
And in your child templates you can override {% block content %} but leaving <head> etc common for all templates:
index.html
{% extends "base.html" %}
{% block content %}
<h1>Welcome to my app</h1>
{% endblock %}
Also you should not write tag like {% endblock BLOCKNAME %}, just {% endblock %}
I'm trying to implement django sekizai app. It is duplicating the js files that i'm adding.
base template:
{% load sekizai_tags %}
...
{% render_block "my_js" %}
template that is using this base:
{% load sekizai_tags %}
<div id="a1" >
{% addtoblock "my_js" %}
<script type="text/javascript" src="{{ MEDIA_URL }}js/my_js.js"></script>
{% endaddtoblock %}
</div>
{% addtoblock "my_js" %}
<script type="text/javascript" src="{{ MEDIA_URL }}js/my_js.js"></script>
{% endaddtoblock %}
Now here the rendered template has rendered twice.But when I tried adding the same script within the div it wasn't duplicated. Would appreciate if someone can shed some light on this!
Also when i try to use {% addtoblock %} in a template rendered by a template tag the script goes missing (It is neither included nor it stays in that template).
Note: The template tags, render_block and addtoblock, are from the django-sekizai package.
{% addtoblock %} and {% endaddtoblock %} have to be inside of a block in templates that inherit another template.
# base.html
<html>
...
{% render_block 'js' %}
{% block js %}{% endblock %}
</html>
# some-page.html
{% inherits 'base.html' %}
{% block js %}
{% addtoblock 'js' %}
<script type="text/javascript" ... />
{% endaddtoblock %}
{% endblock %}
Hope that helps you out.
{% addtoblock %} inside the template (something.html) from an inclusion tag:
from django import template
from django.conf import settings
register = template.Library()
#register.inclusion_tag('something.html', takes_context=True)
def render_something(context, some_arg):
sezikai_ctx_var = getattr(settings, 'SEKIZAI_VARNAME', 'SEKIZAI_CONTENT_HOLDER')
attrs = {
'some_arg': some_arg,
sezikai_ctx_var: context[sezikai_ctx_var]
}
return attrs
I want to use the same {% block %} twice in the same django template. I want this block to appear more than once in my base template:
# base.html
<html>
<head>
<title>{% block title %}My Cool Website{% endblock %}</title>
</head>
<body>
<h1>{% block title %}My Cool Website{% endblock %}</h1>
</body>
</html>
And then extend it:
# blog.html
{% extends 'base.html' %}
{% block title %}My Blog{% endblock %}
# pictures.html
{% extends 'base.html' %}
{% block title %}My Pictures{% endblock %}
# cats.html
{% extends 'base.html' %}
{% block title %}My Cats{% endblock %}
I will get an exception, as Django wants the block to appear only once:
TemplateSyntaxError at /
'block' tag with name 'title' appears
more than once
A quick and dirty solution would be duplicating the block title into title1 and title2:
# blog.html
{% extends 'base.html' %}
{% block title1 %}My Blog{% endblock %}
{% block title2 %}My Blog{% endblock %}
But this is a violation of the DRY principle. It would be very difficult as I have a lot of inheriting templates, and also because I don't wanna go to hell ;-)
Is there any trick or work-around to this problem? How can I repeat the same block in my template, without duplicating all the code?
Use the Django template macros plugin:
https://gist.github.com/1715202 (django >= 1.4)
or
http://www.djangosnippets.org/snippets/363/ (django < 1.4)
django >= 1.4
# base.html
{% kwacro title %}
{% block title %}My Cool Website{% endblock %}
{% endkwacro %}
<html>
<head>
<title>{% usekwacro title %}</title>
</head>
<body>
<h1>{% usekwacro title %}</h1>
</body>
</html>
and
# blog.html
{% extends 'base.html' %}
{% block title %}My Blog{% endblock %}
django < 1.4
# base.html
{% macro title %}
{% block title %}My Cool Website{% endblock %}
{% endmacro %}
<html>
<head>
<title>{% usemacro title %}</title>
</head>
<body>
<h1>{% usemacro title %}</h1>
</body>
</html>
and
# blog.html
{% extends 'base.html' %}
{% block title %}My Blog{% endblock %}
I think that use of the context processor is in this case an overkill. You can easily do this:
#base.html
<html>
<head>
<title>{% block title %}My Cool Website{% endblock %}</title>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
and then:
# blog.html
{% extends 'base.html' %}
{% block content %}
<h1>{% block title %}My Blog{% endblock %}</h1>
Lorem ipsum here...
{% endblock %}
and so on... Looks like DRY-compatible.
You probably don't actually want to use a block but rather to just use a variable:
# base.html
<html>
<head>
<title>{{ title|default:"My Cool Website" }}</title>
</head>
<body>
<h1>{{ title|default:"My Cool Website" }}</h1>
</body>
</html>
You then set the title through the context.
Here's a way I discovered when trying to do the same thing myself:
# base_helper.html
<html>
<head>
<title>{% block _title1 %}{% endblock %}</title>
</head>
<body>
<h1>{% block _title2 %}{% endblock %}</h1>
</body>
</html>
# base.html
{% extends "base_helper.html" %}
# Copy title into _title1 & _title2, using "My Cool Website" as a default.
{% block _title1 %}{% block _title2 %}{% block title %}My Cool Website{% endblock %}{% endblock %}{% endblock %}
Requires an extra file unfortunately, but doesn't require you to pass the title from the view.
you can use {% include subtemplate.html %} more than once. it's not the same as blocks, but does the trick.
There are some discussion here:
http://code.djangoproject.com/ticket/4529
Obviously django core team reject this ticket because they think this is not a common used scenario, however I disagree.
repeat block is simple and clean implementation for this:
https://github.com/SmileyChris/django-repeatblock
template macros is another one, however the author mentioned it's not carefully tested:
http://www.djangosnippets.org/snippets/363/
I used repeatblock.
As an update for anyone coming across this, I've taken the snippet mentioned above and turned it into a template tag library, django-macros, makes the macros more powerful and also implements a repeated block pattern explicitly: django-macros.
Here is a lightweight solution similar to the above do_set and do_get template tag answer. Django allows you to pass the entire template context into a tag which can allow you to define a global variable.
base.html:
<!DOCTYPE html>
<html lang="en">
<head>
{% block head %}
<title>{{ title }}</title>
{% endblock %}
</head>
<body>
<h1>{{ title }}</h1>
</body>
</html>
page.html:
{% extends "base.html" %}
{% block head %}
{% define 'title' 'Homepage | title' %}
{{ block.super }}
{% endblock %}
custom tag (got the idea here: https://stackoverflow.com/a/33564990/2747924):
#register.simple_tag(takes_context=True)
def define(context, key, value):
context.dicts[0][key] = value
return ''
Also don't forget to {% load %} your custom tags or add them to the template options builtins list so you don't have to load them in every template. The only limitation to this approach is the {% define %} has to be called from within a block tag because child templates only render block tags that match the parent tags. Not sure if there is a way around that. Also make sure the define call comes before you try to use it obviously.
Building on Van Gale's suggestion, you could create get and set tags by adding the following to your templatetags.py file:
register = template.Library()
Stateful = {}
def do_set(parser, token):
_, key = token.split_contents()
nodelist = parser.parse(('endset',))
parser.delete_first_token() # from the example -- why?
return SetStatefulNode(key,nodelist)
class SetStatefulNode(template.Node):
def __init__(self, key, nodes):
Stateful[key] = nodes
def render(self, context):
return ''
register.tag('set', do_set)
def do_get(parser, token):
tag_name, key = token.split_contents()
return GetStatefulNode(key)
class GetStatefulNode(template.Node):
def __init__(self, key):
self.key = key
def render(self, context):
return ''.join( [x.render(context) for x in Stateful[self.key]] )
register.tag('get', do_get)
Then set values in one template via {% set foo %}put data here{% endset %} and get them via {% get foo %} in another.
I too have come across the same need for a repeated {% block %} in my template files. The issue is that I want a Django {% block %} to be used in either case of a Django conditional, and I want the {% block %} to be over-writable by subsequent files that may extend the current file. (So in this case, what I want is definitely more of a block than a variable because I'm not technically re-using it, it just appears on either end of a conditional.
The Problem:
The following Django template code will result in a Template Syntax Error, but I think it's a valid "want" to have a defined {% block %} re-used in a conditional (IE, why is the Django parser validating syntax on BOTH ends of a conditional, shouldn't it only validate the TRUTHY condition?)
# This example shows a {{ DEBUG }} conditional that loads
# Uncompressed JavaScript files if TRUE
# and loads Asynchronous minified JavaScript files if FALSE.
# BASE.html
{% if DEBUG %}
<script src="{{MEDIA_URL}}js/flatfile.1.js"></script>
<script src="{{MEDIA_URL}}js/flatfile.2.js"></script>
<script src="{{MEDIA_URL}}js/flatfile.3.js"></script>
<script type="text/javascript">
{% block page_js %}
var page = new $site.Page();
{% endblock page_js %}
</script>
{% else %}
<script type="text/javascript">
// load in the PRODUCTION VERSION of the site
// minified and asynchronosly loaded
yepnope([
{
load : '{MEDIA_URL}}js/flatfiles.min.js',
wait : true,
complete : function() {
{% block page_js %} // NOTE THE PAGE_JS BLOCK
var page = new $site.Page();
{% endblock page_js %}
}
}
)];
</script>
{% endif %}
# ABOUT.html
{% extends 'pages/base.html' %}
{% block page_js %}
var page = new $site.Page.About();
{% endblock page_js %}
The Solution:
You can use an {% include %} to conditionally insert a {% block %} more than once. This worked for me because the Django syntax checker includes only the TRUTHY {% include %}. See the result below:
# partials/page.js
{% block page_js %}
var page = new $site.Page();
{% endblock %}
# base.html
{% if DEBUG %}
<script src="{{MEDIA_URL}}js/flatfile.1.js"></script>
<script src="{{MEDIA_URL}}js/flatfile.2.js"></script>
<script src="{{MEDIA_URL}}js/flatfile.3.js"></script>
<script type="text/javascript">
{% include 'partials/page_js.html' %}
</script>
{% else %}
<script type="text/javascript">
yepnope([
{
load : '{MEDIA_URL}}js/flatfiles.min.js',
wait : true,
complete : function() {
{% include 'partials/page_js.html' %}
}
}
)];
</script>
{% endif %}
I use this answer to keep things dry.
{% extends "base.html" %}
{% with "Entry Title" as title %}
{% block title %}{{ title }}{% endblock %}
{% block h1 %}{{ title }}{% endblock %}
{% endwith %}
There are two easy solutions for this.
The easiest is to put your title into a context variable. You would set the context variable in your view.
If you are using something like generic views and don't have a views.py for pictures, cats, etc. then you can go the way of a custom template tag that sets a variable in the context.
Going this route would enable you to do something like:
{% extends "base.html" %}
{% load set_page_title %}
{% page_title "My Pictures" %}
...
Then in your base.html:
...
{% block title %}{{ page_title }}{% endblock %}
...
<h1>{{ page_title }}</h1>
The selected answer alludes to an easy workaround to wrap one tag inside another in the child template to give them both the same value. I use this for social images like so.
Child template:
{% extends 'base.html' %}
...
{% block meta_image %}
{% block meta_image_secure %}
{% if object.cover_pic %}
{{ object.cover_pic.url }}
{% else %}
https://live-static.welovemicro.com/static/img/device-dark.png
{% endif %}
{% endblock %}
{% endblock %}
...
Then in the parent base.html:
...
<meta property="og:image" itemprop="image" content="{% block meta_image %}https://live-static.welovemicro.com/static/img/device-dark.png{% endblock %}">
<meta property="og:image:secure_url" itemprop="image" content="{% block meta_image_secure %}https://live-static.welovemicro.com/static/img/device-dark.png{% endblock %}">
...
I would suggest using the django-macros library.
To install:
pip install django-macros
And then add the 'macros' app in your INSTALLED_APPS list in settings.py.
After that, load the macros custom tags in your base template and use them like that:
{# base.html #}
{% load macros %}
{% macro title %}
{% block title %} My Cool Website {% endblock %}
{% endmacro %}
<html>
<head>
<title> {% use_macro title %} </title>
</head>
<body>
<h1> {% use_macro title %} </h1>
</body>
</html>
In twig you can make this like:
# base.html
<html>
<head>
<title>{{ block('title') }}</title>
</head>
<body>
<h1>{{ block('title') }}</h1>
</body>
</html>
# blog.html
{% extends 'base.html' %}
{% block title %}My Blog{% endblock %}
# pictures.html
{% extends 'base.html' %}
{% block title %}My Pictures{% endblock %}
# cats.html
{% extends 'base.html' %}
{% block title %}My Cats{% endblock %}