Django url template with query parameters - django

I'm trying to pass query parameters via my view into a link, but it escapes me on how to actually achieve this in a good way.
My template is as following:
<a class="link-button" href="{% url 'videos:index' %}?tag={{ tag }}&page={{ next }}">Next</a>
This returns what I want:
http://127.0.0.1:8000/videos/?tag=1&page=2
While this works, it's quite fragile, does not handle None values and there must be a better way of doing this.
I tried to pass this via the urltemplate tag but it did not seem to be what I was looking for since it requires url config changes for path:
{% url 'videos:index' page=next tag=tag %}
Is there an actual way of doing this or a template tag I can use to get the parameters? I tried searching for this but it gave me a lot of old results and more path urls, like: /videos/page-1/tag-1/ which I'm not looking for.
I was hoping to do something like:
Next

There is no builtin support, but you can add one yourself. You can for example define the following template tag. We can for example construct files in boldface:
app/
templatetags/
__init__.py
urlparams.py
Where in urlparams.py, we define:
from django import template
from urllib.parse import urlencode
register = template.Library()
#register.simple_tag
def urlparams(*_, **kwargs):
safe_args = {k: v for k, v in kwargs.items() if v is not None}
if safe_args:
return '?{}'.format(urlencode(safe_args))
return ''
In the template, we can then load the template tag and then use it like with:
{% load urlparams %}
Next
Note that strictly speaking, the URL parameters can contain the same key multiple times. This is here not possible. So we can not generate all possible URL parameters, but this is usually quite rare, and in my opinion not a good idea in the first place.

you can use default template filter and update your example
<a class="link-button" href="{% url 'videos:index' %}?tag={{ tag|default:'' }}&page={{ next|defaul:'' }}">Next</a>
output for empty tag and page is:
http://127.0.0.1:8000/videos/?tag=&page=
but if you want to dont print None Tag in url you must your own template tag or filter. simply you can write this template filter
#register.filter
def print_query_param(value, key)
if value and key:
return "%s=%s&" % (key, value)
and you can use it as below
<a class="link-button" href="{% url 'videos:index' %}?{{ tag|print_query_param:'tag' }}{{ next|print_query_param:'page' }}">Next</a>

Template tag urlencode
Use the template tag urlencode:
example
Small note:
Note that there is no need to pass the param names themselves through urlencode, since in this case they are literals. If the param names were not literals, you would need to, like this:
example

Related

Django template: How to pass formatted string to include tag

I am new to Django and Django template, I know Django Template is kind of restrictive compare to Rails.
So I am including a template in email like:
{% include "./partials/_info_row.html" with value=f'{request_count} requests' %}
but this throws error: TemplateSyntaxError: Could not parse the remainder: ''{request_count} requests'' from 'f'{request_count} requests''
Is there a way to pass formatted string like this to include tag?
Exception is raised because you can't use f-strings in Django templates - templates language is not actually a Python.
According to doc's there is not need to explicitly pass context variable when using include:
Loads a template and renders it with the current context.
If you need to pass a combined value (context plus something else like "requests" string), you can use simple tag:
tags.py
#register.simple_tag(takes_context=True)
def your_custom_tag(context, format_string):
request_count = context['request_count']
return f'{request_count} requests'
templates
{% with r_count=your_custom_tag %}
{% include "./partials/_info_row.html" with value=r_count %}
{% include "./partials/_info_row.html" with value=request_count|stringformat:'s'|add:' requests' %}
request_count|stringformat:'s' - convert number to string
some_var|add:'requests' - concat strings
Thanks #Chamel and #crazyzuber. I used combination of your answers. Created custom filter.
I knew about custom tag. But I wanted to avoid that because this was not generic tag, it will get used only at one place, so I wanted a solution for which I dont have to write custom tag. But custom tags solution works because it allows you to format string in anyway, which was not possible using existing built-in.
Btw I used #register.filter
#register.filter(is_safe=True)
def request_count_text(count):
return f"{count} request{ 's' if count > 1 else '' }"
and using it as:
{% include "./_info_row.html" with value=request_count|request_count_text %}
This solves my issue.

How to pass a template tag from one template to another in django 2

I am new to Django, and template tags and HTML and have a template where I use a for loop to fill out bootstrap cards from a database. In the model I has a field Resume_link that has a PDF file. All I want to is have the PDF file displayed in a different template file and not in the card where it is too small to read. (Since I am in the loop when someone clicks the link, I just want the specific resume connected to that card to be shown in the new template.) So all I think I should need to do is somehow either pass the the index of the loop, or another variable that identifies the correct database entry. But I think I am missing something fundamental and don't understand how to pass the value of a template tag in one template another template. Is there some way to pass a variable along with the url to a view so the variable can be used to make a new template tag in the desired template?
{% for key in myres %}
...fill out other parts of cards and create the below link...
<a href="{% url "show_pdf" %}" style="font-size: 20px">
{% endfor %}
where show_pdf is the view where I want to show the whole PDF file.
and that template show_pdf is
What I would like to do is be able to pass the key.Resume_link.url, or if not that the pk for that database table to the show_pdf template.
The view for show_pdf is
def show_pdf(request):
template = 'show_pdf.html'
myres=Research.objects.all()
context = {'myres': myres}
return render(request,'mainapp/show_pdf.html', context)
you can pass the current pdf id in the url and access it.
def show_pdf(request, pdf_id):
template = 'show_pdf.html'
myres=Research.objects.get(id=pdf_id)
context = {'myres': myres}
return render(request,'mainapp/show_pdf.html', context)
In you urls.py you must write like this
path('show_pdf/?P<int:pdf_id>/', views.show_pdf, name="show_pdf")
In HTML write <a href="{% url "show_pdf" key.id %}">
Instead of:
<a href="{% url "show_pdf" %}">
... you would include a parameter, e.g.:
<a href="{% url "show_pdf" pdf_id %}">
The resulting URL would now be formatted as indicated by the corresponding urlconf entry, for instance:
http://my.web.site/resumes/show_pdf/1343
(if pdf_id = 1343 ...)
You must specify as many parameters as the corresponding urlconf entry expects, and you may use either positional or keyword syntax (but not both).
Then, when the user clicks on the link, the View specified in that urlconf will get control, and it will have the specified parameter value (1343 ...) as one of its arguments. You'd select the PDF and send it to the template to be properly presented to the user.

Getting request.path in django template tags

I want to create a custom filter for django templates. I've got some currency pairs (which are links) that I pass to my html page so I need to check if current url is equal to a currency pair from my list, then I gotta skip it.
For example, my url is:
https://website.com/usd/eur/
So if there's a pair USD/EUR, it won't be shown on my page.
To do this, I need to loop over all pairs and compare them to request.path value. So, how can I get it within my template tags ?
You can directly receive request into template tags like -
#register.simple_tag(name='new_tag')
def new_tag(request):
path = request.path
....
and then in your html use it like {% new_tag request %}.

djangocms-snippet which contains {% %} doesnot show up as placeholder content

I am trying to make my footer a editable from frontend.. using placeholder and inserting footer snippet.
yet, my footer snippet contains django template language
e.g.
Terms and Conditions
as a result, the placeholder content is not showing up, if i remove the django specific things
Terms and Conditions
it is working.
how can I make it work with django reverse url?
I could have given hard coded path but i want the path translatable so i need to reverse by url's name.
If I've got you right, just create custom tag and store templates in database:
from django.template import RequestContext, Template
#register.simple_tag
def footer(request):
snippet = Snippet.object.get(name='footer')
template = Template(snippet.html)
return template.render(RequestContext(request))
{% footer request %}
use this syntax:
{% url 'terms_conditions' as the_url %}
Terms and Conditions
use smartsnippets
These has the capability of rendering django tags

Factor a small piece of HTML [django]

Can I factor a small piece of html code with Django template ?
I have, for example, a lot of images like this:
<img src="/xxxx/xxxx/xxxxxx.jpg">
Can I replace that by {{ image_xxx }} ?
Create a custom template tag:
from django import template
register = template.Library()
#register.simple_tag
def image_by_value(value):
return "/xxxx/xxxx/xxxxxx.jpg"
You can use this in your template as follows:
<img src="{% image_by_value 001 %}">
The value 001 is then passed to the variable value and you can use it to construct the string that contains the image path (i.e., "/xxxx/xxxx/xxxxxx.jpg").
Yes. I suggest creating a custom template tag for it. See the part about inclusion tags.