Django: check for exact url in request using regex - django

I need to check if the url is exactly:
http://127.0.0.1:8000/shop/
and based on this render a header.
If it is, for example:
http://127.0.0.1:8000/shop/stickers/stickers-por-hoja/medida-y-cantidad
Header shouldn't render.
I've read you can do something like this:
{% if "/shop/$" in request.path %}
{% include 'header.html' %}
{% endif %}
But this doesn't work. On the other hand this works, but is not what I need:
{% if "/shop/" in request.path %}
{% include 'header.html' %}
{% endif %}
So, Can I use regex in the if condition?

Create a context processor has_shop_in_url.py having this code below.
import re
def has_shop(request):
shop_in_request = your_regex_validation
return {
'has_shop_in_url': any([shop_in_request]) }
Add that context processor
TEMPLATES = [
{
.....
'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_module.has_shop_in_url.has_shop' # YOUR PROCESSOR
],
},
},
]
Now it is available for your whole web application. In template just write {{has_shop_in_url}}. Your can see True/False.

You could move the regex check into the view and add a field to the context for the template like so:
class MyView(View):
def action(self, request, *args, **kwargs):
shop_in_request = re.findall(r"/shop/$", request.path)
context = {"include_header": any(shop_in_request)}
return render(template, context)
Then in your view you could use:
{% if include_header %}
{% include 'header.html' %}
{% endif %}

Create a template tag to do that.
The url whitelisted must be somewhere in the settings. For example you can add something like this
HEADER_WHITELIST_URLS = (
'regex1',
'regex2',
)
2) Your template tags will check the current URL and if one of the regex matches, you can render your header. In a hypothetical version2, you can also add the header to show for a specific regex.
Use this snippet as starting point for your template tag
import datetime
from django import template
from django.conf import settings
register = template.Library()
#register.simple_tag(takes_context=True)
def render_header(context, format_string):
regexs = settings.HEADER_WHITELIST_URLS
# maybe you can add some try/exception if the settings is not available.
for regex in regexs:
# test the regex with the url in the context.
# if matches return the code to render the header and break
return None
Check here for more details about the template tags: https://docs.djangoproject.com/en/2.1/howto/custom-template-tags/#writing-custom-template-tags

Related

How to display Model in each HTML template?

But create a request in each functions inside views.py I do not want.
Is it possible to output the model in each template using only one request?
I tried to use templateetags but
that so
#register.simple_tag(takes_context=True)
def header_categories(context):
return Categorie.objects.all().order_by('id')
what is like that
#register.simple_tag(takes_context=True)
def header_categories(context):
categories = Categorie.objects.all().order_by('id')
args = {}
for cat in categories:
args[cat.text] = {
'id':cat.id,
}
if cat.parent:
args[cat.text]['parent_id'] = cat.parent.id
args[cat.text]['parent_text'] = cat.parent.text
return args
Nothing works correctly
{% for cat in header_categories %}
cat.text
{% endfor %}
I tried through js
var arr = {%header_categories%}
but django changes everything
{'dresses': {'id': 19},
Before going deeper into your question, I think you should have
{% for cat in header_categories %}
{{ cat.text }}
{% endfor %}
You need to make a custom context processor (See Using RequestContext [Django docs]). What this would do is add a variable to the context for each template. Quoting the documentation:
The context_processors option is a list of callables – called
context processors – that take a request object as their argument and return a dictionary of items to be merged into the context.
In some suitable app of yours make a file named context_processors.py and add this code in it:
def header_categories(request):
return {'header_categories': Categorie.objects.all().order_by('id')}
Now in your settings in the TEMPLATES settings add this context processor to the list context_processors, so it should look like:
[
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'your_app.context_processors.header_categories',
]
Now in your templates you can simply write:
{% for cat in header_categories %}
{{ cat.text }}
{% endfor %}

Template rendering (Django): [duplicate]

mydict = {"key1":"value1", "key2":"value2"}
The regular way to lookup a dictionary value in a Django template is {{ mydict.key1 }}, {{ mydict.key2 }}. What if the key is a loop variable? ie:
{% for item in list %} # where item has an attribute NAME
{{ mydict.item.NAME }} # I want to look up mydict[item.NAME]
{% endfor %}
mydict.item.NAME fails. How to fix this?
Write a custom template filter:
from django.template.defaulttags import register
...
#register.filter
def get_item(dictionary, key):
return dictionary.get(key)
(I use .get so that if the key is absent, it returns none. If you do dictionary[key] it will raise a KeyError then.)
usage:
{{ mydict|get_item:item.NAME }}
Fetch both the key and the value from the dictionary in the loop:
{% for key, value in mydict.items %}
{{ value }}
{% endfor %}
I find this easier to read and it avoids the need for special coding. I usually need the key and the value inside the loop anyway.
You can't by default. The dot is the separator / trigger for attribute lookup / key lookup / slice.
Dots have a special meaning in template rendering. A dot in a variable
name signifies a lookup. Specifically, when the template system
encounters a dot in a variable name, it tries the following lookups,
in this order:
Dictionary lookup. Example: foo["bar"]
Attribute lookup. Example: foo.bar
List-index lookup. Example: foo[bar]
But you can make a filter which lets you pass in an argument:
https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-filters
#register.filter(name='lookup')
def lookup(value, arg):
return value[arg]
{{ mydict|lookup:item.name }}
For me creating a python file named template_filters.py in my App with below content did the job
# coding=utf-8
from django.template.base import Library
register = Library()
#register.filter
def get_item(dictionary, key):
return dictionary.get(key)
usage is like what culebrón said :
{{ mydict|get_item:item.NAME }}
I had a similar situation. However I used a different solution.
In my model I create a property that does the dictionary lookup. In the template I then use the property.
In my model: -
#property
def state_(self):
""" Return the text of the state rather than an integer """
return self.STATE[self.state]
In my template: -
The state is: {{ item.state_ }}
Environment: Django 2.2
Example code:
from django.template.defaulttags import register
#register.filter(name='lookup')
def lookup(value, arg):
return value.get(arg)
I put this code in a file named template_filters.py in my project folder named portfoliomgr
No matter where you put your filter code, make sure you have __init__.py in that folder
Add that file to libraries section in templates section in your projectfolder/settings.py file. For me, it is portfoliomgr/settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, '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',
],
'libraries':{
'template_filters': 'portfoliomgr.template_filters',
}
},
},
]
In your html code load the library
{% load template_filters %}
Since I can't comment, let me do this in the form of an answer:
to build on culebrón's answer or Yuji 'Tomita' Tomita's answer, the dictionary passed into the function is in the form of a string, so perhaps use ast.literal_eval to convert the string to a dictionary first, like in this example.
With this edit, the code should look like this:
# code for custom template tag
#register.filter(name='lookup')
def lookup(value, arg):
value_dict = ast.literal_eval(value)
return value_dict.get(arg)
<!--template tag (in the template)-->
{{ mydict|lookup:item.name }}
env: django 2.1.7
view:
dict_objs[query_obj.id] = {'obj': query_obj, 'tag': str_tag}
return render(request, 'obj.html', {'dict_objs': dict_objs})
template:
{% for obj_id,dict_obj in dict_objs.items %}
<td>{{ dict_obj.obj.obj_name }}</td>
<td style="display:none">{{ obj_id }}</td>
<td>{{ forloop.counter }}</td>
<td>{{ dict_obj.obj.update_timestamp|date:"Y-m-d H:i:s"}}</td>

Want to resolve a dictionary whose key is a field in a model [duplicate]

mydict = {"key1":"value1", "key2":"value2"}
The regular way to lookup a dictionary value in a Django template is {{ mydict.key1 }}, {{ mydict.key2 }}. What if the key is a loop variable? ie:
{% for item in list %} # where item has an attribute NAME
{{ mydict.item.NAME }} # I want to look up mydict[item.NAME]
{% endfor %}
mydict.item.NAME fails. How to fix this?
Write a custom template filter:
from django.template.defaulttags import register
...
#register.filter
def get_item(dictionary, key):
return dictionary.get(key)
(I use .get so that if the key is absent, it returns none. If you do dictionary[key] it will raise a KeyError then.)
usage:
{{ mydict|get_item:item.NAME }}
Fetch both the key and the value from the dictionary in the loop:
{% for key, value in mydict.items %}
{{ value }}
{% endfor %}
I find this easier to read and it avoids the need for special coding. I usually need the key and the value inside the loop anyway.
You can't by default. The dot is the separator / trigger for attribute lookup / key lookup / slice.
Dots have a special meaning in template rendering. A dot in a variable
name signifies a lookup. Specifically, when the template system
encounters a dot in a variable name, it tries the following lookups,
in this order:
Dictionary lookup. Example: foo["bar"]
Attribute lookup. Example: foo.bar
List-index lookup. Example: foo[bar]
But you can make a filter which lets you pass in an argument:
https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-filters
#register.filter(name='lookup')
def lookup(value, arg):
return value[arg]
{{ mydict|lookup:item.name }}
For me creating a python file named template_filters.py in my App with below content did the job
# coding=utf-8
from django.template.base import Library
register = Library()
#register.filter
def get_item(dictionary, key):
return dictionary.get(key)
usage is like what culebrón said :
{{ mydict|get_item:item.NAME }}
I had a similar situation. However I used a different solution.
In my model I create a property that does the dictionary lookup. In the template I then use the property.
In my model: -
#property
def state_(self):
""" Return the text of the state rather than an integer """
return self.STATE[self.state]
In my template: -
The state is: {{ item.state_ }}
Environment: Django 2.2
Example code:
from django.template.defaulttags import register
#register.filter(name='lookup')
def lookup(value, arg):
return value.get(arg)
I put this code in a file named template_filters.py in my project folder named portfoliomgr
No matter where you put your filter code, make sure you have __init__.py in that folder
Add that file to libraries section in templates section in your projectfolder/settings.py file. For me, it is portfoliomgr/settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, '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',
],
'libraries':{
'template_filters': 'portfoliomgr.template_filters',
}
},
},
]
In your html code load the library
{% load template_filters %}
Since I can't comment, let me do this in the form of an answer:
to build on culebrón's answer or Yuji 'Tomita' Tomita's answer, the dictionary passed into the function is in the form of a string, so perhaps use ast.literal_eval to convert the string to a dictionary first, like in this example.
With this edit, the code should look like this:
# code for custom template tag
#register.filter(name='lookup')
def lookup(value, arg):
value_dict = ast.literal_eval(value)
return value_dict.get(arg)
<!--template tag (in the template)-->
{{ mydict|lookup:item.name }}
env: django 2.1.7
view:
dict_objs[query_obj.id] = {'obj': query_obj, 'tag': str_tag}
return render(request, 'obj.html', {'dict_objs': dict_objs})
template:
{% for obj_id,dict_obj in dict_objs.items %}
<td>{{ dict_obj.obj.obj_name }}</td>
<td style="display:none">{{ obj_id }}</td>
<td>{{ forloop.counter }}</td>
<td>{{ dict_obj.obj.update_timestamp|date:"Y-m-d H:i:s"}}</td>

Sending context with request, and {% if %} not working properly

I have a problem trying to figure out why below will render an html page showing 'hi' and 1, instead of just 1.
views method.
def index(request):
context = {
'test' : 1,
}
return render(request, 'index.html', context)
template html. Rendering index.html will show both 'hi' and 1. But there's no user in context, so why is the if user going through?
{% if user %}
<h1>hi</h1>
{% endif %}
{% if test %}
<h1>{{ test }}</h1>
{% endif %}
The answer is Django's builtin context processor called django.contrib.auth.context_processors.auth. It is enabled by default which means an auth.User object representing the currently logged-in user is sent to all templates with the name user automatically.
From docs:
The context_processors option is a list of callables – called context processors – that take a request object as their argument and return a dictionary of items to be merged into the context.
In the default generated settings file, the default template engine contains the following context processors:
[
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
]
if there is a user logged in django will create a AUTH_USER_MODEL representing the currently logged-in user. Also from the request object you can access the user model without specifying context. For example if a user is logged in you can do request.user.username and the username will appear in the template.

django template inheritance and context

I am reading the definitive guide to django and am in Chapter 4 on template inheritance. It seems that I am not doing something as elegant as should be possible as I am having to duplicate some code for the context to appear when calling the child view. Here is the code in views.py:
def homepage(request):
current_date = datetime.datetime.now()
current_section = 'Temporary Home Page'
return render_to_response("base.html", locals())
def contact(request):
current_date = datetime.datetime.now()
current_section = 'Contact page'
return render_to_response("contact.html", locals())
It seems redundant to have to include the current_date line in each function.
Here is the base html file that homepage calls:
<html lang= "en">
<head>
<title>{% block title %}Home Page{% endblock %}</title>
</head>
<body>
<h1>The Site</h1>
{% block content %}
<p> The Current section is {{ current_section }}.</p>
{% endblock %}
{% block footer %}
<p>The current time is {{ current_date }}</p>
{% endblock %}
</body>
</html>
and a child template file:
{% extends "base.html" %}
{% block title %}Contact{% endblock %}
{% block content %}
<p>Contact information goes here...</p>
<p>You are in the section {{ current_section }}</p>
{% endblock %}
If I don't include the current_date line when calling the child file, where that variable should appear is blank.
You can pass a variable to every template by using a Context Processor:
1. Adding the context processor to your settings file
First, you will need to add your custom Context Processor to your settings.py:
# settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
'myapp.context_processors.default', # add this line
'django.core.context_processors.auth',
)
From that you can derive that you will need to create a module called context_processors.py and place it inside your app's folder. You can further see that it will need to declare a function called default (as that's what we included in settings.py), but this is arbitrary. You can choose whichever function name you prefer.
2. Creating the Context Processor
# context_processors.py
from datetime import datetime
from django.conf import settings # this is a good example of extra
# context you might need across templates
def default(request):
# you can declare any variable that you would like and pass
# them as a dictionary to be added to each template's context:
return dict(
example = "This is an example string.",
current_date = datetime.now(),
MEDIA_URL = settings.MEDIA_URL, # just for the sake of example
)
3. Adding the extra context to your views
The final step is to process the additional context using RequestContext() and pass it to the template as a variable. Below is a very simplistic example of the kind of modification to the views.py file that would be required:
# old views.py
def homepage(request):
current_date = datetime.datetime.now()
current_section = 'Temporary Home Page'
return render_to_response("base.html", locals())
def contact(request):
current_date = datetime.datetime.now()
current_section = 'Contact page'
return render_to_response("contact.html", locals())
# new views.py
from django.template import RequestContext
def homepage(request):
current_section = 'Temporary Home Page'
return render_to_response("base.html", locals(),
context_instance=RequestContext(request))
def contact(request):
current_section = 'Contact page'
return render_to_response("contact.html", locals(),
context_instance=RequestContext(request))
So, you can use django.views,generic.simple.direct_to_template instead of render_to_response. It uses RequestContext internaly.
from django.views,generic.simple import direct_to_template
def homepage(request):
return direct_to_template(request,"base.html",{
'current_section':'Temporary Home Page'
})
def contact(request):
return direct_to_template(request,"contact.html",{
'current_section':'Contact Page'
})
Or you can even specify it directly at urls.py such as
urlpatterns = patterns('django.views.generic.simple',
(r'^/home/$','direct_to_template',{
'template':'base.html'
'extra_context':{'current_section':'Temporary Home Page'},
}),
(r'^/contact/$','direct_to_template',{
'template':'contact.html'
'extra_context':{'current_section':'Contact page'},
}),
For django v1.8+ variables returned inside context processor can be accessed.
1. Add the context processor to your TEMPLATES list inside 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.context_processor_file.func_name', # add this line
],
},
},
]
2. Create new file for context processor and define method for context
context_processor_file.py
def func_name(request):
test_var = "hi, this is a variable from context processor"
return {
"var_for_template" : test_var,
}
3. Now you can get the var_for_template in any templates
for example, add this line inside: base.html
<h1>{{ var_for_template }}</h1>
this will render:
<h1>hi, this is a variable from context processor</h1>
for updating templates to django 1.8+ follow this django doc