I'm using a custom Django (v1.5.5) model Widget used to contain HTML code (using a TextField) to be placed in certain places of different pages and allow staff users change the contents easily through the Django admin backend.
This approach works perfectly with HTML, CSS and Javascript code. Using the following syntax at the templates:
{{ widget.content|safe }}
However, I'd also like to be able to put Django code (using templatetags, calling methods...) within it, but this Django code does NOT get executed and instead it's directly printed as if it was plain text.
Is there any way to execute Django code using the safe filter? Or am I missing another filter? Maybe I'd have to use a custom filter or templatetag... Any ideas?
Thank you!
Django doesn't have a template tag/filter like that by default. I'm using this in one of my projects:
class IncludeString(ttag.Tag):
template_src = ttag.Arg()
def render(self, context):
data = self.resolve(context)
try:
t = loader.get_template_from_string(data['template_src'])
except Exception, e:
return u"error rendering template: %s" % unicode(e)
return t.render(context)
class Meta:
name = "include_string"
register.tag(IncludeString)
And use it like {% include_string variable_name_with_template_content %}. This implementation uses django-ttag, but I think something like the following should work, too (untested):
#register.simple_tag(takes_context=True)
def include_string(context, template_src):
try:
t = loader.get_template_from_string(template_src)
return t.render(context)
except Exception, e:
return u"error rendering template: %s" % unicode(e)
Based on #sk1p's answer, I've created a Django simple_tag that takes an HTML string (which can contain "Django code") and the context (which is absolutely necessary here). Then I just render it and return. That's it!
I created a file called smart_html.py that contains:
from django import template
from django.template import Template
register = template.Library()
#register.simple_tag(takes_context=True)
def render_html(context, html):
return Template(html).render(context)
Then, from the templates I just have to do:
{% load smart_html %}
{% render_html widget.content %}
Related
I want to filter the objects in a model using custom filter tag, but I got nothing.
Here is the profile_tag.py in the templatetags folder.
from django import template
register = template.Library()
from ..models import Profile
#register.inclusion_tag('register/profile.html')
def filter_profile(request):
profile = Profile.objects.filter(user=request.user)
return {'profile' : profile}
I loaded the tag in the html file: {% load profile_tags %}
Then I tried to print {{profile.user}} in different ways, but nothing is showing up.
If I have an error, can you fix it or can you give me another solution to filter the model by the user.
note: I don't want to use the Profile.objects.filter(user=request.user) in the views.py file.
Thanks.
When I try to call this in my template
{% if member.departments.relationship(department).is_manager is True %}
I get this error
Could not parse the remainder: '(department).is_manager' from 'member.departments.relationship(department).is_manager'
But the same call works when I debug my view
(Pdb) member.departments.relationship(department).is_manager
True
Here is my view
def department_detail(request, uid):
department = Department.nodes.get(uid=uid)
return render(request, 'department/detail.html', {'department': department,})
To solve it, I made use of templatetags. Fun and powerful to learn:
Added /templatetags to same directory as models.py
Added /templatetags/init.py
Added /templatetags/department_extras.py
department_extras.py:
from django import template
from django.utils.safestring import mark_safe
register = template.Library()
#register.filter
def check_is_manager(member, department):
if member.departments.relationship(department).is_manager is True:
html_response = """<i class="fa fa-user-tie" title="Manager"></i>"""
else:
html_response = ""
return mark_safe(html_response)
then in template:
{% load department_extras %}
{{member|check_is_manager:department}}
Disclaimer: If I was using a standard ORM then I would not have this problem, and I am only using it for visual effect, not business logic. If it weren't for the fact that 3 views and other models will need the same functionality, then I would have passed in an additional argument to the template.
I like templatetags because they are almost like sub-views that can act as common denominators across views so that you don't have to keep passing in supplemental data in your arguments of each view.
I am trying to put a login form in every page in my web that uses django.contrib.auth.views.login. I created a templatetag in templatetags/mytags.py, where I define a function called get_login wich looks like this:
#register.inclusion_tag('registration/login.html', takes_context=True)
def get_login(context):
...
return {'formLogin': mark_safe(AuthenticationForm())}
...and in base.html:
{% load mytags %}{% get_login %}
The problem now is that the template (registration/login.html) doesnt recognize {{ formLogin.username }},{{ formLogin.password }}... and so on.
What am I missing?
mark_safe returns an instance of django.utils.safestring.SafeString, not a form, so those lookups will fail. I don't think there's anything wrong with directly returning the form (that's what all the generic views in django.contrib.auth do when populating templates, for instance). Just change your return statement to
return {'formLogin': AuthenticationForm()}
and it should work.
{% include 'django.contrib.auth.views.login' %}
I don't want to write everything by hand.. I hate this really, django full of automatic stuff.
Goal is to include registration/login.html into base.html, so that I could have this form in every page
If I include only template itself (registration/login.html), problem appears that "form.login", I mean "form" var is not defined because this one comes from VIEW which called when you going to login url. So how can I call that view MANUALLY with include or at least to grab django.contrib.auth.views.login variables by my self in my own view and pass then to base.html?
P.s. It's not just about login form, I think there will be more situations like this
I have found better solution in #django irc.
They called inclusion tags
I'll give you my code, because I got lot's of problem learning new stuff in django =)
file: templatetags/form_login.py
from django import template
register = template.Library()
from django.contrib.auth.forms import AuthenticationForm
#register.inclusion_tag('registration/login.html')
def form_login():
return { 'form': AuthenticationForm() }
Now you can have your form anywhere, this will prerender template and THAT'S IT! no stupid context processors which requires to modify whole project settings.py, which is really sux if you writing stand alone little application..
If you need login-form on every page
Create a context processor:
def login_form_processor(request):
return {
'login_form': LoginForm(request.POST or None)
}
Add it to settings.CONTEXT_PROCESSORS.
Include the template for login form:
{% with login_form as form %}
{% include "registration/login.html" %}
{% endwith %}
You can also make you form lazy-loading, so form will not be created until it is used for the first time.
from django.utils improt functional
def login_form_processor(request):
create_login_form = lambda: LoginForm(request.POST or None)
return {
'login_form': functional.lazy(create_login_form, LoginForm)
}
But I guess you won't want the lazy-loading feature, because login-form is cheap to initialize.
Reusing views
Concerning the "grabbing variables" part from your question: you cannot grab variable from view. Django view is method which returns response object. You can not get variables from response. However some of views accept extra_context and other attributes. Those attributes allow you to configure those views in urls, or to wrap them with your own view, for example:
def my_login_view(request):
some_extra_data = get_some_data()
extra_context = {
'some_extra_var': some_extra_data
}
return login_view(request, extra_context=extra_context, template="my_template.html")
This is not exactly grabbing the variables from views, more like augmentation of existing views.
If you expect to have more situations like this, do less data-porcessing in views. Call some methods which checks for permissions. Collect some data from context-processors. Return rendered response. Now you can reuse the data in other views.
You can specify the action on the form html to point to the URL that accesses the corresponding view.
If you want a form, say called as login_form always populated in all templates, then put it in the context_processors.
Browsing the code for django.contrib.auth.views, you will see that the variables form, site and *site_name* are passed to the template.
Either you (1) provide your custom registration form or (2) you can just import django.contrib.auth.forms.AuthenticationForm in your view if you want to use it.
Hi I need to refresh my custom template tag --right_side.py-- via Ajax. Is there a way to import the template tag in the view and return it as HttpResponse because I don't want to give up my custom template tag (it works great in other pages) nor code a new view action which is really similar to it.
Having a link to call with Ajax or loading it in the view inside
if request.isAjax():
Are both fine for me.
I find it really useful when refreshing an area with ajax. So thought it would be good to share it:
First you import the custom template tag you coded in your view file.
from your_app_name.templatetags import your_tag_name
And then you use it like this:
return HttpResponse(your_tag_name.your_method(context))
That worked for me and I got the template tag as response from server and refreshed the div with that result.
I had this same question awhile ago, I was loading HTML snippets with AJAX which I had already written as template tags. And I was trying to avoid duplicating the code in two places.
This is what I came up with to render a template tag from a view (called via ajax):
from django.template import RequestContext, Template
def myview(req):
context = RequestContext({'somearg':"FooBarBaz"})
template_string = """
{% load my_tag from tagsandfilters %}
{% my_tag somearg %}
"""
t = Template(template_string)
return HttpResponse(t.render(context))
You could create a template just containing your templatetag and nothing else. Then you would have in right_side.html:
{%load cems_templatetags%}
{%right_side%}
and in the view something like:
if request.isAjax():
return render_to_response('right_side.html',RequestContext(request))
I found this solution :
from templatetags_file_name import my_templatetag
return render (request,'path/to/template.html', my_templatetag(parameter) )
And, in my "templatetags_file_name", "my_templatetag" is like that :
#register.inclusion_tag('path/to/template.html')
def my_templatetag(parameter):
#my operations
return locals()