Is there a way to access the ADMINS variable of the settings module from an any arbitrary template without adding manually adding it into the context before being rendered, similar to how request is available in any template using RequestContext if django.core.context_processors.request is in TEMPLATE_CONTEXT_PROCESSORS?
You can write your own context processor (which is a regular function that has request as parameter):
from django.conf import settings
def admin_emails(request):
return { 'ADMINS': settings.ADMINS }
and add path.to.my.context_processor.admin_emails to TEMPLATE_CONTEXT_PROCESSORS.
I'd use a template tag like discussed for this question:
Can I access constants in settings.py from templates in Django?
Specifically I use the code from this answer: https://stackoverflow.com/a/6343321/2250326
With that you can get at the AMDINS in your templates like this:
{% value_from_settings "ADMINS" as admins %}
{% for admin in admins %}
Name: {{ admin.0 }}<br />
Email: {{ admin.1 }}
{% endfor %}
Related
In django admin, we can define custom templates per app. In this case, I'm customising the app_index.html template for my application.
I'd like to add a few graphs and other to that page. Now that I've overridden the template, how can I override the corresponding view method?
I thought about making a custom AdminSite and override the app_index() (see https://github.com/django/django/blob/master/django/contrib/admin/sites.py#L511) method, but I have more than one application in my django installation, all of which will have a custom app_index.html.
What's the best way to add context to the app_index.html template?
Don't know if this is the best way, but it can be done with template
tags. Here is how I did it:
# <app>/templatetags/erp.py
register = template.Library()
#register.assignment_tag
def erp_get_tasks ():
return Task.objects.exclude (done=True).order_by ('priority')
.
# <app>/templates/admin/erp/app_index.html
{% extends "admin/app_index.html" %}
{% load erp %}
...
{% block footer %}
{% erp_get_tasks as tasks %}
{% for task in tasks %}
...
I have created a template tag and trying to loop through the results from the template tag
but I don't get any results
tags.py
from django import template
from loadprograms import dbcontext
register = template.Library()
#register.simple_tag
def get_category():
x = dbcontext.DBContext()
results = x.executequery("Select name from Categories")
categories = [each[0] for each in results]
return categories
template code
{% load category_tags %}
{% get_category %}
{% for each in get_category %}
{{ each }}
{% endfor %}
The {% get_category %} prints all the categories without any issues but the for loop stmt
that loop through the results does not work
What could be the problem?
To make this change in your tag, you'll have to set a variable in the context, but if your objective is to have a list of categories available in templates, just like you would have passed it in from the view - then you need to write a template context processor, which will allow all views to have this variable in their context.
A template context processor is just a method that adds to the request context, by returning a dictionary. Think of it like a view function, that just returns a context.
from .models import Categories
def cat_names(request):
return {'category_names': Category.objects.values_list('name', flat=True)}
To activate this context processor, you have to do a few things:
Add the above code to a file called template_processors.py in the same place as your models.py and views.py.
In your settings.py, add the fully-qualified name of the method to the TEMPLATE_CONTEXT_PROCESSORS setting, making sure you don't override the defaults. To do this easily, import the default settings first, then add to it:
from django.conf.default_settings import TEMPLATE_CONTEXT_PROCESSORS as TCP
TEMPLATE_CONTEXT_PROCESSORS = TCP + ('yourapp.template_processors.cat_names',)
Use the render shortcut, which will make sure the context is correctly passed.
In your views, you can now just do this:
from django.shortcuts import render
def home(request):
return render(request, 'home.html')
In your home.html, you can now do:
{% for name in category_names %}
{{ name }}
{% endfor %}
I've got a Django template in HTML. I would like to pass a variable to this template using a context. However, when I render the template Django fills the spaces that reference this variable with the string specified by the TEMPLATE_STRING_IF_INVALID setting (I tested this).
Here's the relevant URLconf:
from django.conf.urls import patterns, url
from users import views
urlpatterns = patterns('',
url(r'^$', views.users),
url(r'(?P<pk>\d+)/$', views.userdetail),
)
and here's the view it references:
from django.template import RequestContext, loader
...
def userdetail(request, pk):
user = get_object_or_404(User, pk=pk)
template = loader.get_template('users/userdetail.html')
context = RequestContext(request, {'user': user})
return HttpResponse(template.render(context))
I'm fairly certain it's due to a syntax error in specifying the context but after looking at it for an hour I can't find one. I'm happy to post additional code if you think it may be relevant. Can anyone spot my mistake?
Template for those interested:
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif%}
<h1> You are viewing the page for the individual user {{ user.name }} </h1>
This user has created the following posts:
{% for post in user.post_list %}
{{ post.title }}</li>
{% endfor %}
<p>
Created on {{ user.creation_date }}
</p>
The OP wrote:
My supervisor just came around and fixed it really quickly. The issue is that templates have some predefined keywords. User is one of these keywords so django was upset that I was passing it {'user':user} in the context. Changing to {'customuser':user} avoids the collision with the django keyword and fixes this issue.
I am using Django flatpages and would like to implement some logic in a template based on a user session variable.
eg.
{% if session.my_var %}
YES
{% else %}
NO
{% endif %}
Problem is that session object is not defined in flatpage context.
Create a TEMPLATE_CONTEXT_PROCESSOR which is then used by the RequestContext (see docs).
def session(request):
return { 'session': request.session }
In django I have a view that fills in a template html file but inside the html template I want to include another view that uses a different html template like so:
{% block content %}
Hey {{stuff}} {{stuff2}}!
{{ view.that_other_function }}
{% endblock content %}
Is this possible?
Yes, you need to use a template tag to do that. If all you need to do is render another template, you can use an inclusion tag, or possibly just the built in {% include 'path/to/template.html' %}
Template tags can do anything you can do in Python.
https://docs.djangoproject.com/en/3.0/howto/custom-template-tags/
[Followup]
You can use the render_to_string method:
from django.template.loader import render_to_string
content = render_to_string(template_name, dictionary, context_instance)
You'll either need to resolve the request object from the context, or hand it in as an argument to your template tag if you need to leverage the context_instance.
Followup Answer: Inclusion tag example
Django expects template tags to live in a folder called 'templatetags' that is in an app module that is in your installed apps...
/my_project/
/my_app/
__init__.py
/templatetags/
__init__.py
my_tags.py
#my_tags.py
from django import template
register = template.Library()
#register.inclusion_tag('other_template.html')
def say_hello(takes_context=True):
return {'name' : 'John'}
#other_template.html
{% if request.user.is_anonymous %}
{# Our inclusion tag accepts a context, which gives us access to the request #}
<p>Hello, Guest.</p>
{% else %}
<p>Hello, {{ name }}.</p>
{% endif %}
#main_template.html
{% load my_tags %}
<p>Blah, blah, blah {% say_hello %}</p>
The inclusion tag renders another template, like you need, but without having to call a view function. Hope that gets you going. The docs on inclusion tags are at: https://docs.djangoproject.com/en/3.0/howto/custom-template-tags/#inclusion-tags
Using your example and your answer to Brandon's response, this should work for you then:
template.html
{% block content %}
Hey {{stuff}} {{stuff2}}!
{{ other_content }}
{% endblock content %}
views.py
from django.http import HttpResponse
from django.template import Context, loader
from django.template.loader import render_to_string
def somepage(request):
other_content = render_to_string("templates/template1.html", {"name":"John Doe"})
t = loader.get_template('templates/template.html')
c = Context({
'stuff': 'you',
'stuff2': 'the rocksteady crew',
'other_content': other_content,
})
return HttpResponse(t.render(c))
Someone created a template tag that loads a view. I've tried it, and it works. The advantage of using that template tag is that you don't have to rewrite your existing views.