I'm sure the answer is right there and I'm not seeing it. How can I render a RichTextBlock to remove the wrapping <div class="rich-text">?
{% include_block block %} and {{ block.value }} both give the wrapping div.
Unfortunately this is hard-coded and can't currently be overridden - see https://github.com/wagtail/wagtail/issues/1214.
I solved this by creating a custom template tag
In your project create a file in your templatetags directory (e.g. templatetags/wagtailcustom_tags.py) with content along the following.
from django import template
from django.utils.safestring import mark_safe
from wagtail.core.rich_text import RichText, expand_db_html
register = template.Library()
#register.filter
def richtext_withclasses(value, classes):
if isinstance(value, RichText):
html = expand_db_html(value.source)
elif isinstance(value, str):
html = expand_db_html(value)
elif value is None:
html = ""
else:
raise TypeError(
"'richtext_withclasses' template filter received an invalid value; expected string, got {}.".format(
type(value)
)
)
return mark_safe('<div class="' + classes + '">' + html + "</div>")
Then in your templates load the template tag
{% load wagtailcustom_tags %}
and render richtext fields with the custom classes (or no classes at all)
{{ myfield | richtext_withclasses:"my custom class" }}
Related
I want to convert something like that id,name to something like that "id","name" in django template.
I looked at django template built in tags but none of them works.
Does anyone have an idea to achieve it?
you can do this by writing a custom Template Tag:
besides your templates folder add a directory named templatetags.
create convert_tags.py in your templatetags directory:
# convert_tags.py
from django import template
register = template.Library()
#register.filter()
def add_quotes(value: str):
""" Add double quotes to a string value """
return f'"{value}"'
In your templates load convert_tags:
<!-- template.html -->
{% load convert_tags %}
{{ your_str|add_quotes }}
You can simply
"{{ id }}", "{{ name }}"
Or you can define a custom template tag to do this dynamically
from django import template
register = template.Library()
#register.simple_tag
def quote(str):
return f'"{str}"'
And in your template
{{ id | quote }}, {{ name | quote }}
Thanks for everyone,
I solved it by creating a custom template tag
Here's the code :
from django import template
register = template.Library()
def add_quote(var):
return '"{0}"'.format(var)
#register.filter()
def add_quotes(value):
""" Add double quotes to a string value """
excluded_fields = value.split(',')
return ",".join(add_quote(i) for i in excluded_fields)
I use this pattern:
class PersonAdmin(admin.ModelAdmin):
readonly_fields = ('address_report',)
def address_report(self, instance):
return format_html(...)
Source: docs about readonly_fields
Now I would like to use a custom templatetag in the Python method address_report().
What is the best way to call it?
I tried to called my templatetag directly, but this just returns a dictionary, not html.
I think you'll have to create a template from string. That way you can use any template tags or variables you want.
Example:
from django.template import Template, Context
def address_report(...):
# create template
t = Template("""
{% load custom_tag_module %}
<p>
Hello, {{ name }}! <br>
{% custom_tag %}
</p>
""")
# create context
c = Context({'name': 'World'})
# render template, mark safe and return
return mark_safe(t.render(c))
I'm trying to be DRY with my Django templates, and have some code that I mix with CSS for a simple hover-over popup. I'd like to reuse the code, but the contents of my popup will be HTML that may well span over multiple lines. Is it possible to stuff multi-line strings into a template variable?
I tried doing something funky with blocks and block.super but that only seems to work when extending (not include)
Here's an example of what I'd like to do. Is it possible?
index.html
<body>
<h2>My Popup</h2>
{% include "snippets/popup.html" with class="p" spantext="Hover me" popupdiv="""
<h2>This is a popup!</h2>
<ul>
<li>Something</li>
<li>Something else</li>
</ul>
"""
%}
</body>
snippets/popup.html
<div class="{{ class }}">
<span class='pointer'>{{ spantext }}</span>
<div class="popup">
{{ popupdiv }}
</div>
</div>
I know it's not possible to have multi-line template tags in Django, but is there any way round this, other than squashing all my div html onto one line, and escaping any quotes?
Cheers
It turns out "Parsing until another template tag" is what I was after. http://www.djangobook.com/en/2.0/chapter09.html
Here's my code:
tags.py (in the templatetags folder)
from django import template
from django.template.loader import get_template
from django.template.base import Node, TemplateSyntaxError
register = template.Library()
class PopupNode(Node):
def __init__(self, nodelist, class_name, spantext):
self.nodelist = nodelist
self.class_name = class_name
self.spantext = spantext
def render(self, context):
popup_html = get_template("ordersystem/snippets/popup.html")
context.update({
'class' : self.class_name,
'spantext' : self.spantext,
'popupdiv' : self.nodelist.render(context)
})
return popup_html.render(context)
#register.tag('popup')
def show_popup(parser, token):
nodelist = parser.parse(('endpopup',))
tokens = token.split_contents()
if len(tokens) != 4:
raise TemplateSyntaxError("show_popup is in the format 'popup with class=X spantext=Y")
try:
context_extras = [t.split("=")[1].strip('"') for t in tokens[2:]]
except IndexError:
raise TemplateSyntaxError("show_popup is in the format 'popup with class=X spantext=Y")
parser.delete_first_token()
return PopupNode(nodelist, *context_extras)
Then within my html file I can just do:
{% popup with class_name=management spantext=Manage %}
<h2>This is a popup!</h2>
<ul>
<li>Something</li>
<li>Something else</li>
</ul>
{% endpoup %}
The best way should be to create a templatetags in your module with an inclusion tag.
https://docs.djangoproject.com/en/dev/howto/custom-template-tags/
So imagine your are YourModule yourModule with a folder templatetags and the file popup_tag.py
yourModule/
---- views.py
---- models.py
---- templates/
---- snippet/
---- popup.html
---- templatetags/
---- __init__.py
---- popup_tag.py
Your popup_tag.py could look like the following lines :
from django import template
register = template.Library()
def show_pop_up(class, span_text, popupdiv):
return {'class': class,
'span_text': span_text,
'pop_up_div': pop_up_div}
register.inclusion_tag('snippet/popup.html')(show_popup)
Then, you just have to call your tag in your template index.html.
{% load popup_tag %}
{% show_popup "class" "span_text" "popupdiv" %}
Is there an out-of-the-box way of checking if a template exists before including it in a Django template? Alternatives are welcome too but some of them would not work due to the particular circumstances.
For example, here's an answer to a slightly different question. This is not what I'm looking for:
How to check if a template exists in Django?
Assuming include doesn't blow up if you pass it a bad template reference, that's probably the best way to go. Your other alternative would be to create a template tag that essentially does the checks in the link you mentioned.
Very basic implementation:
from django import template
register = template.Library()
#register.simple_tag
def template_exists(template_name):
try:
django.template.loader.get_template(template_name)
return "Template exists"
except template.TemplateDoesNotExist:
return "Template doesn't exist"
In your template:
{% template_exists 'someapp/sometemplate.html' %}
That tag isn't really all that useful, so you'd probably want to create one that actually adds a variable to the context, which you could then check in an if statement or what not.
I encountered this trying to display a template only if it exists, and wound up with the following template tag solution:
Include a template only if it exists
Put the following into yourapp/templatetags/include_maybe.py
from django import template
from django.template.loader_tags import do_include
from django.template.defaulttags import CommentNode
register = template.Library()
#register.tag('include_maybe')
def do_include_maybe(parser, token):
"Source: http://stackoverflow.com/a/18951166/15690"
bits = token.split_contents()
if len(bits) < 2:
raise template.TemplateSyntaxError(
"%r tag takes at least one argument: "
"the name of the template to be included." % bits[0])
try:
silent_node = do_include(parser, token)
except template.TemplateDoesNotExist:
# Django < 1.7
return CommentNode()
_orig_render = silent_node.render
def wrapped_render(*args, **kwargs):
try:
return _orig_render(*args, **kwargs)
except template.TemplateDoesNotExist:
return CommentNode()
silent_node.render = wrapped_render
return silent_node
Access it from your templates by adding {% load include_maybe %} at the top of your template, and using {% include_maybe "my_template_name.html" %} in code.
This approach has the nice side effect of piggy-backing the existing template include tag, so you can pass in context variables in the same way that you can with a plain {% include %}.
Switch based on whether a template exists
However, I wanted some additional formatting on the embedding site if the template existed. Rather than writing an {% if_template_exists %} tag, I wrote a filter that lets you work with the existing {% if %} tag.
To this end, put the following into yourapp/templatetags/include_maybe.py (or something else)
from django import template
from django.template.defaultfilters import stringfilter
register = template.Library()
#register.filter
#stringfilter
def template_exists(value):
try:
template.loader.get_template(value)
return True
except template.TemplateDoesNotExist:
return False
And then, from your template, you can do something like:
{% load include_maybe %}
{% if "my_template_name"|template_exists %}
<div>
<h1>Notice!</h1>
<div class="included">
{% include_maybe "my_template_name" %}
</div>
</div>
{% endif %}
The advantage of using a custom filter over using a custom tag is that you can do things like:
{% if "my_template_name"|template_exists and user.is_authenticated %}...{% endif %}
instead of using multiple {% if %} tags.
Note that you still have to use include_maybe.
I needed to conditionally include templates if they exist but I wanted to use a variable to store the template name like you can do with the regular {% include %} tag.
Here's my solution which I've used with Django 1.7:
from django import template
from django.template.loader_tags import do_include
register = template.Library()
class TryIncludeNode(template.Node):
"""
A Node that instantiates an IncludeNode but wraps its render() in a
try/except in case the template doesn't exist.
"""
def __init__(self, parser, token):
self.include_node = do_include(parser, token)
def render(self, context):
try:
return self.include_node.render(context)
except template.TemplateDoesNotExist:
return ''
#register.tag('try_include')
def try_include(parser, token):
"""
Include the specified template but only if it exists.
"""
return TryIncludeNode(parser, token)
In a Django template it might be used like this:
{% try_include "template-that-might-not-exist.html" %}
Or, if the template name is in a variable called template_name:
{% try_include template_name %}
include accepts variables:
{% include template_name %}
so you could do the check in your view.
I'm trying to use WTForms with Django & a MongoEngine/MongoDB database backend. The forms are outputting properly, but I can't for the life of me get the labels to show up.
Here is my template code:
{% load wtforms %}
<form>
{% for f in form %}
{{ f.label }}: {% form_field f %}<br/>
{% endfor %}
</form>
This is what I am passing in the view:
form = StrandForm()
return render_to_response('create_strand.html', locals(), context_instance = RequestContext(request))
The StrandForm class I have tried both creating from the WTForm mongoengine extension's model_form class, and from WTForm's Form class. The label exists in the view, I can print it to the console and it shows the rendered form label, but somehow it gets lost when transferring to the template. Am I doing something wrong?
Django 1.4 has a new feature: do_not_call_in_templates attribute.
If you set it on wtforms.Field class, every child class inherits and all fields will work fine in django templates.
import wtforms
wtforms.Field.do_not_call_in_templates = True
Now following code works as expected:
{% load wtforms %}
{{ f.label }}: {% form_field f %}
I encountered the same problem today. It has to do with the way WTForms is programmed so that it will work with many different templating libraries. Django 1.3 will only see f as it's HTML string even though it has other attributes.
In order to fix this you must add a template tag to retrieve the attribute.
Add the following to your projects hierarchy:
templatetags
templatetags / init.py
templatetags / templatetags
templatetags / templatetags / init.py
templatetags / templatetags / getattribute.py
Then in your settings.py file, add the following line to INSTALLED_APPS
'templatetags',
Open up getattribute.py and paste the following code:
from django import template
from django.conf import settings
register = template.Library()
#register.tag
def getattribute(parser, token):
try:
tag_name, tag_object, tag_function = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError("%r tag requires two arguments" % token.contents.split()[0])
return getattrNode(tag_object, tag_function)
class getattrNode(template.Node):
def __init__(self, tag_object, tag_function):
self.tag_object = tag_object
self.tag_function = tag_function
def render(self, context):
return getattr(context[self.tag_object], self.tag_function)()
This will allow you to use the follow code whenever you're inside a template and need an attribute that won't show up:
{% load getattribute %}
{% getattribute OBJECT ATTRIBUTE %}
In your case:
{% getattribute f label %}
Hope that helped!