Basically trying to do
{% url dynamic_url_name dynamic_parameter_name=dynamic_parameter_value %}
Tried the simplest approach of
{{entry}}
{% include 'mainsite/children/title_template.html' with
the_title=title_text
is_title_page=True
entries_of="title"
belongs_to="profile"
belongs_to_url_arg="user"
belongs_to_url_arg_value="author"
%}
But unfortunately this resulted in utter failure of
From this I can tell that parameters can't be context variables, so what I can try to do next is to simply unpack a dictionary as I would do inside python with something like
{% url **{dynamic_parameter_name:dynamic_parameter_value} %}
But I have no idea if it is possible inside django templates, and if possible how?
My urls look like
re_path(r'^title/(?P<title_text>[a-zA-Z0-9-]+)/$', TitlePage.as_view(), name='title')
re_path(r'^user/(?P<user>[a-zA-Z0-9-]+)/$', ProfilePage.as_view() ,name='profile')
And I the url is choosen either by a context variable or in an include tag, hence it is a variable.
{% url url_variable xxx=value %}
Now, url_variable is already a part of django, url tag accepts variable as it's first argument. But the xxx is not always the same, rather it changes according to url_variable, in this particular case; if url_variable is title, I want xxx to be title_text and if it is profile I want it to be user.
The parameter name is held in belongs_to, so if this was a regular python function, I could've simply done
url(url_variable, **{belongs_to: value})
and it would've unpacked it with the correct parameter name. So I need some kind of equivalency of this in template processor
I think you're overcomplicating things. You haven't shown your views themselves, but I can't see why they couldn't all take a commonly-named parameter - say, param - that does the specific work. So the URLs could be:
re_path(r'^title/(?P<param>[a-zA-Z0-9-]+)/$', TitlePage.as_view(), name='title')
re_path(r'^user/(?P<param>[a-zA-Z0-9-]+)/$', ProfilePage.as_view() ,name='profile')
and now you can do
{% url dynamic_url_name param=dynamic_parameter_value %}
**kwargs are not specifically supported as a parameter for the {% url %} tag, but there are a few workwarounds.
If you have a path in urlpatterns defined as:
path('myurl/<str:some>/<str:thing>', name='myurl')
Then you could have a filetoinclude.html:
My Url
And then in your main.html:
{% include 'filetoinclude.html' with urlname='myurl' some="aaa" thing="bbb" %}
And when you render you will have something like:
My Url
But obviously the issue is that maybe you want to address specific parameters of the URL when you reverse it. For this reason you could create a templatetag like:
from django.urls import reverse
from django import template
register = template.Library()
#register.simple_tag
def dynamic_url(urlname, **kwargs):
return reverse(urlname, kwargs=kwargs)
and then in your filetoinclude.html you could do:
{% load url_extended %}
{% dynamic_url urlname some=some thing=thing %}
which will yield the same URL as before.
Related
I have page_obj in a template which was returned from a ListView view. Now, I wanted to create links to several pages before and after the current page. Therefore, I wanted to slice page_obj.paginator.page_range this way: page_obj.paginator.page_range[page_obj.number-3:page_obj.number+4]. This works in django shell but for some reason when I did it a template, there is a Template Syntax Error, Could not parse the remainder: '[page_obj.number-3:page_obj.number+4]' from 'page_obj.paginator.page_range[page_obj.number-3:page_obj.number+4]'. Is there a workaround for this case?
P.S. I know I can do it using the whole page_obj.paginator.page_range and then using if statements to check if a page is in the required range, but I thought it's a bit inefficient.
As stated in my comment Django Template Language does not include normal python syntax. The reason for this is Django aims to separate the logic and design of the website. If there is need to perform somewhat complicated logic you either need to use template tags or filters.
For your need either an inclusion tag would work or a simple filter that would take the page_range and return a sliced version of it. A template filter here would not be very useful considering we can only pass one argument to it, meaning it would not be very customizable. Let's assume that your pagination would look very similar or perhaps you would pass the template you use to the tag.
Firstly you need to create a templatetags sub-package in your app and then in that you would add files (e.g. pagination_tags.py) which would contain your tags. The layout would be something like:
your_app/
__init__.py
models.py
templatetags/
__init__.py
pagination_tags.py
views.py
Now in your file pagination_tags.py you want to write your tags. As a reference you may read the howto on Custom template tags and filters in the documentation.
Firstly we declare register which is an instance of template.Library. After which we would write our template tags / filters. We will use an inclusion_tag:
from django import template
register = template.Library()
#register.inclusion_tag('pagination_tag.html')
def show_pagination(page_obj, **kwargs):
left = kwargs.get('left', 3)
right = kwargs.get('right', 4)
pages_iter = page_obj.paginator.page_range[page_obj.number - left:page_obj.number + right]
template = kwargs.get('template', 'default_pagination_template.html')
return {**kwargs, 'page_obj': page_obj, 'pages_iter': pages_iter, 'template': template}
Now we will have a simple template named pagination_tag.html that will simply extend the template name either passed as a keyword argument or default_pagination_template.html:
{% extends template %}
Now in default_pagination_template.html or any other template we can use all the variables in the dictionary that our function show_pagination returns:
{% for page_num in pages_iter %}
Display page links here, etc.
{% endfor %}
You can modify this implementation as per your needs. I will also leave the design and implementation of default_pagination_template.html upto you.
Now in your template where you want to use this, first we will load these tags. Then we will use them:
{% load pagination_tags %}
...
{% show_pagination page_obj left=5 right=6 template="some_custom_template.html" %}
Situation
I'm writing a checker program that checks Django templates. For example I want to check if all Django templates that use url template tag, use it with quotes on first parameter so that it is Django 1.5 compatible. Also I want to check that they have included {% load url from future %} in their templates.
For example if my program parses the following Django template, I want it to raise an exception.
{% extends 'base.html' %}
<td>
<a href="{% url first second %}">
</a>
</td>
But this template should get parsed without exception.
{% extends 'base.html' %}
{% load url from future %}
<td>
<a href="{% url 'first' second %}">
</a>
</td>
I'm not limited to this simple example. I have other parsings to do. For example I want to check how many load template tags are present in the template.
Question
How can I elegantly solve this parsing problem?
I don't want to use regular expressions.
I this Django it self has some utilities in this regard. I think using them is a good idea, but I don't know how.
I want to run the program separately from Django. So I don't want Django to run the program itself (with render_to_response). (This is important)
Code
Please show me some code that can solve the example I mentioned. I want to detect whether {% load url from future %} is in the code. Also I want to check every url template tag and check if the first argument is quoted.
Bonus:
I want to be able to see the rendered HTML that Django generates from this template, and do my HTML parsing on it. (for example with PyQuery)
You say...
I want to check if all Django templates that use url
template tag, use it with quotes on first parameter so that it is
Django 1.5 compatible.
...and...
I don't want to use regular expressions.
...because...
the result of that might become a huge spaghetti code
...but, frankly, writing a parser from scratch is likely to be even messier than using a regular expression. I don't see what's so messy about a regex as simple as something like...
"{% *url +[^']"
...and I doubt there's a non-regex-based solution that's as terse as that.
With regards to...
Also I want to check that they have included
{% load url from future %} in their templates.
If your intention is to ensure Django 1.5 compatibility, this is pointless. According to the Django 1.5 release notes, the new-style url tag syntax is enabled by default, so the line {% load url from future %} won't have any effect.
And in versions prior to 1.5, it's much simpler just to put...
import django.template
django.template.add_to_builtins('django.templatetags.future')
...at the bottom of your settings.py and be done with it. :-)
You can also use the compile_string method.
>>> from django.template.base import *
>>> settings.configure()
>>> compile_string("<a href='ab'></a>{% cycle 'row1' 'row2' as rowcolors %}", None)
>>> [<Text Node: '<a href='ab'></a>'>, <django.template.defaulttags.CycleNode object at 0x10511b210>]
The compile string method is utilized by the Template class and is the method used to produce the node list.
Tested in Django 1.8 Alpha.
https://github.com/django/django/blob/1f8bb95cc2286a882e0f7a4692f77b285d811d11/django/template/base.py
Next code still uses django, but it can check if syntax is correct:
>>> from django.template import Template
>>> from django.template.defaulttags import URLNode
>>> t = Template("{% load url from future %}\n{% url projects_list company.slug %}")
>>> for node in t.nodelist:
... if isinstance(node, URLNode):
... for arg in node.args: print(arg)
...
company.slug
>>> t2 = Template('{% load url from future %}\n{% url "projects_list" company.slug }')
>>> for node in t2.nodelist:
... print(node)
...
<django.template.defaulttags.LoadNode object at 0x32145d0>
<Text Node: '
{% url "projects_list" c'>
>>>
As you see last node is not URLNode
My problem occurs when I try to pass 3 variables to my template tag which I guess takes one or 2 inputs. So any ideas on how to pass 3 template variables to my template tag and here is my code:
views.py:
from shoghlanah.models import *
register = template.Library()
#register.simple_tag
def get_messages(sender_id,receiver_id,task_id):
sender = UserProfile.objects.get(id = sender_id)
receiver =UserProfile.objects.get(id = receiver_id)
task = Task.objects.get(id=task_id)
return messages
message.html :
the url.id and the task_id are template variables
{{ get_messages request.user.id usr.id task_id }}
it gives me an error : Could not parse the remainder: ' request.user.id usr.id task_id' from 'get_messages request.user.id usr.id task_id'
For a django tag, you need to use {% %}, not the double curly brackets. The double braces signify outputting a value.
See the docs for more.
(Just as a note, I presume that is an extract, but you will also need to {% load %} your tag too.)
I am using a Django Paginator and I want to have multiple available get parameters, such as:
page=1
sort_by=price
However, in my template tags I have:
Showing items sorted by {{ SORT_PARAM }}.
Showing {{ ITEMS_PER_PAGE }} items per page.
{% if has_prev %}
Previous |
{% endif %}
However, this does not preserve the other GET variables. What I mean is, if I'm viewing
page/?page=1&sort_by=price
and I click the link in the template fragment above, I will go to
page=2
instead of
page=2&sort_by=price
What I mean is, the a href does not preserve the other GET parameters.
One solution is I could type all the possible GET parameters in the a href, such as
Previous
but this will become less scalable the more arguments I want to add to my browsing. I'm guessing there should be an automated way to obtain all GET parameters, and then pass those and one more?
This one http://djangosnippets.org/snippets/1592/ looks cleaner
You can create a 'parameter-string'. Let's supose that in your code you have:
my_view( request, page, options):
sort_choices = {P:'price',N:'name', ...}
n_item_choices = {'S':5, 'L':50, 'XL':100)
ascending_descending_choices = {'A':'', 'D':'-'}
...
then you can concatenat options as:
options='P-S-D' #order by price, 5 items per page, descending order
encode opions as:
Previous
then, in urls.py capture options and in view:
my_view( request, page, options):
... #choides ....
try:
optionsArray = options.split('-')
sort_by = sort_choices[ optionsArray[0] ]
n_ites_page = n_item_choices[ optionsArray[1] ]
asc_or_desc = ascending_descending_choices[ optionsArray[2] ]
...
except:
somebody is playing ....
with this method you are free to add more paginations options without modify urls.py, all you need is to append options at the end of string options . This has advantages but also some dangers: I hope you can identify risks.
With Django's Pagination - preserving the GET params is simple.
First copy the GET params to a variable (in view):
GET_params = request.GET.copy()
and send it to the template in via context dictionary:
return render_to_response(template,
{'request': request, 'contact': contact, 'GET_params':GET_params}, context_instance=RequestContext(request))
Second thing you need to do is use it specify it in the url calls (href) in the template - an example (extending the basic pagination html to handle extra param condition):
{% if contacts.has_next %}
{% if GET_params %}
next
{% else %}
next
{% endif %}
{% endif %}
Source - Posted same answer.
I want to add a context variable in Django, so that I could define its value on per-application basis, or leave it empty.
Example:
apps/someapp/views.py:
def_context_var('app_name', 'Calendar')
templates/base.html:
{% if app_name %}You are in {{ app_name }} app.{% endif %}
....
{% if app_name %}Subsections of {{ app_name }}: ...{% endif %}
I considered the following:
Declare a variable in the app (in a view, or in URLs), and make a context processor. But I can't understang how to extract that var given the request object.
Put decorators on views. Hm, I don't like the idea: too much boilerplate or duplicated code.
#1 but nicer: make methods (like in the example above) that are executed on server restart, write the data into a dict, then a context processor somehow (how?) gets the application name and extracts the data from the dict. Where do I put the method, the dict, how does the context processor know where the view object is in?
You can call resolve(request.path) in a context processor to resolve the current url. See the django documentation on resolve for its return values, especially app_name.