I'm building an app in Django in which I have a layout where I have the navbar and I extend this layout to each page.
In order to have the navbar to receive the proper variables from the view I have to write the same code on each view. There has to be a way to write this code once and affect directly the layout so I won't need to type it multiple times but I haven't found the answer.
How can I write the function one time? Something like a global variable in Django I guess.
I hope I managed to explain myself ok, thanks in advance!
first you create context_processors.py somewher in your app.
then you write the function needed, something like:
from .models imoprt Somemodel
def alltimefunc(request):
something = Somemodel.objects.all()
return something
finally you add it in the settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'your_app_name.context_processors.alltimefunc', #here
],
},
},
]
Here comes context processors handy in these kind of situations. You can write a function and register it with template engine in settings.py file. This way you can write code once and it will affect directly to the layout.
Related
I am currently working on a project which heavily uses Jinja2 for template rendering. The relevant code looks like this:
settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.jinja2.Jinja2',
'DIRS': [os.path.join(BASE_DIR, 'templates'),
os.path.join(BASE_DIR, 'request/templates'),
os.path.join(BASE_DIR, 'core/templates'),
os.path.join(BASE_DIR, 'vaux/templates')],
'APP_DIRS': True,
'OPTIONS': {
'environment': 'myapp.jinja2.environment',
'extensions': ['jinja2.ext.i18n', 'jinja2.ext.do', 'vcom.jinja2.blockcache', 'jinja2.ext.with_'],
'autoescape': False,
'bytecode_cache': FileSystemBytecodeCache(CACHE_DIR),
'auto_reload': True,
'lstrip_blocks': True,
'trim_blocks': True,
},
},
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages'
],
},
},
]
myapp/jinja2.py file looks like this:
def environment(**options):
env = Environment(**options)
env.globals.update({
'some_global_context_var': 'Some value'
})
# how do I access request ? So that I can write something like request.META['HTTP_HOST']
So my goal now is to try to get access to the request object, so that I can write something like request.META['HTTP_HOST']. Is there any way to do that ?
Prior to this, I tried to come up with a global context var using Django's vanilla `context processors' concept, but with Jinja2 it is not so easy.
You can access request from globals as documented in Django templates Jinja2 documentation
The default configuration is purposefully kept to a minimum. If a
template is rendered with a request (e.g. when using render()), the
Jinja2 backend adds the globals request, csrf_input, and csrf_token to
the context. Apart from that, this backend doesn’t create a
Django-flavored environment. It doesn’t know about Django filters and
tags. In order to use Django-specific APIs, you must configure them
into the environment
What is the standard, preferred way to make settings available to templates in Django 1.8? Currently, I define a custom context processor in my project and then reference it in my TEMPLATES OPTIONS setting. I've looked through the docs but didn't find this issue mentioned. This previous Stackoverflow question says to do what I'm doing but it's over two years old and I'm wondering if there's a newer preferred method. If I've learned one thing from recently upgrading Django, it's to do things the way the framework wants you to do them. You'll have fewer problems this way.
Thanks.
# utils/context_processors.py
from profile.models import UserProxy
from conf.settings import base as base_settings
def global_constants(request):
"""Constants that are available to all templates."""
return {
'site_name': base_settings.SITE_NAME,
'media_url': base_settings.MEDIA_URL
}
# myproject/settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug', # default
'django.template.context_processors.request', # default
'django.contrib.auth.context_processors.auth', # default
'django.contrib.messages.context_processors.messages', # default
'utils.context_processors.global_constants', # project
],
},
},
]
I have an object called Groups that is used in every single page on my website. However, Django only passes in Python objects to html through render_to_response and I can't render to response everytime something happens to the groups object.
How do I maintain this object(as in make it respond to adding and deletion) and produce it in every Django template that I have without calling render_to_response?
write a template context processor:
#my_context_processors.py
def include_groups(request):
#perform your logic to create your list of groups
groups = []
return {'groups':groups}
then add it in your settings file:
#settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
"django.core.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"path.to.my_context_processors.include_groups",
)
now a variable groups will be available to you in all your templates
If you need data added to more than one template contexts you should look into achieving that via your own template context processor.
You need to create template context processor to pass an object to each request. Here is some example
#tu_context_processor.py
from setting.models import Business
def include_business(request):
business = Business.objects.all().last()
return {'business': business}
in your settings file:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [TEMPLATE_DIR],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'core.tu_context_processor.include_business',
],
},
},
]
now a variable business will be available to you in all your templates
tested in Django 4
I have come to a point where I need to pass certain variables to all of my views (mostly custom authentication type variables).
I was told writing my own context processor was the best way to do this, but I am having some issues.
My settings file looks like this
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.contrib.messages.context_processors.messages",
"sandbox.context_processors.say_hello",
)
As you can see, I have a module called 'context_processors' and a function within that called 'say_hello'.
Which looks like
def say_hello(request):
return {
'say_hello':"Hello",
}
Am I right to assume I can now do the following within my views?
{{ say_hello }}
Right now, this renders to nothing in my template.
My view looks like
from django.shortcuts import render_to_response
def test(request):
return render_to_response("test.html")
The context processor you have written should work. The problem is in your view.
Are you positive that your view is being rendered with RequestContext?
For example:
def test_view(request):
return render_to_response('template.html')
The view above will not use the context processors listed in TEMPLATE_CONTEXT_PROCESSORS. Make sure you are supplying a RequestContext like so:
def test_view(request):
return render_to_response('template.html', context_instance=RequestContext(request))
According to the django docs you can use render as a shortcut instead of render_to_response with the context_instance argument:
Alternatively, use the render() shortcut which is the same as a call to render_to_response() with a context_instance argument that forces the use of a RequestContext.
Let's say you have a file structure like this:
YourDjangoProject
├───project
│ ├───__init__.py
│ ├───asgi.py
│ ├───settings.py
│ ├───urls.py
│ └───wsgi.py
├───.env
├───manage.py
└───db.sqlite3
1) Anywhere, create a context_processors.py file
I'll create one in the project folder (with settings.py):
YourDjangoProject
└───project
├───...
└───context_processors.py
2) Create a function in context_processors.py that accepts a HttpRequest object as an argument and returns a dictionary
A context processor is just a function that accepts an HttpRequest object as an argument and returns a dictionary.
Like this:
# project/context_processors.py
def site_email(request):
return {'site_email': 'example#gmail.com'}
3) Add this to your context_processors setting in settings.py (at the bottom for security reasons)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'config' / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'project.context_processors.site_email', # <- New context processor here
],
},
},
]
Now you'll be able to access the 'site_email' template variable on every single django template across your whole site.
Happy coding!
Since Django 1.8 you register your custom context processors like this:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
'templates'
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'www.context_processors.instance',
],
},
},
]
assuming your context processor is in app www in context_processors.py
If you’re using Django’s render_to_response() shortcut to populate a template with the contents of a dictionary, your template will be passed a Context instance by default (not a RequestContext). To use a RequestContext in your template rendering, use the render() shortcut which is the same as a call to render_to_response() with a context_instance argument that forces the use of a RequestContext.
I have a small typography related templatetag library that I use on almost every page. Right now I need to load it for each template using
{% load nbsp %}
Is there a way to load it "globally" for all views and templates at once? Putting the load tag into a base template doesn't work.
There is an add_to_builtins method in django.template.loader. Just pass it the name of your templatetags module (as a string).
from django.template.loader import add_to_builtins
add_to_builtins('myapp.templatetags.mytagslib')
Now mytagslib is available automatically in any template.
It will change with Django 1.9 release.
Since 1.9, correct approach will be configuring template tags and filters under builtins key of OPTIONS - see the example below:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'builtins': ['myapp.builtins'],
},
},
]
Details:
https://docs.djangoproject.com/en/dev/releases/1.9/#django-template-base-add-to-builtins-is-removed
In django 1.7 just replace for from django.template.base import add_to_builtins
In Django 1.9 there is an libraries dictionary of labels and dotted Python paths of template tag modules to register with the template engine. This can be used to add new libraries or provide alternate labels for existing ones.
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
'libraries': { # Adding this section should work around the issue.
'custom_tags' : 'myapp.templatetags.custom_tags',#to add new tags module.
'i18n' : 'myapp.templatetags.custom_i18n', #to replace exsiting tags modile
},
},
},
]