Dynamically replace all urls to full absolute url in template - django

I have a template which I am going to send as an email.
Thus I need to have absolute full urls (along with protocol and domain name) instead of relative ones.
The content in the email is going to come dynamically from database (entered using ckeditor, so I CAN NOT do something like {{ protocol }}{{ domain_name }}{% static '' %}. This would work only for static files. However the media content uploaded via ckeditor will recide in media files and I have absolutely no control over it.
Also i cant use javascript as it is an email template.
Currently I have built a python function which scans the entire template after rendering and prepends the protocol and domain name to every src attribute in img tag and all href attributes.
I would like to know if any better way exists

You can use request.build_absolute_uri and make a custom template tag in order to used when rendering your mail template.
Example
#templatetags/url_helper.py
#register.simple_tag()
def full_uri(request, relative_url):
return request.build_absolute_uri(realtive_url)
Then ...
{# Some template.html #}
{% full_uri request some_img.url as full_img_url %}
<img src={{ full_img_url }} />

Related

Django template nested include passing variables

I use django template index.html to render the frontpage. It includes another template to create a link icon. This template url_icon.html includes another template icon.html. When passing the arguments down the way, I face with an error. How to fix it?
index.html
.
.
.
{% include "url_icon.html" with name="return" url="/" %}
.
.
.
url_icon.html
{% include "icon.html" with icon={{ name }} %}
icon.html
<img src="/static/images/{{ name }}.png" />
Causing an error:
Could not parse the remainder: '{{' from '{{'
it looks like there are a few things you can do to improve/fix this. Addressing #1 and #2 should fix your issue. I've also added suggestions for best practices that would probably require refactoring (#3, #4).
It looks like you need to remove the curly-braces from name inside the {% include %} tag. Context variables can be used inside tags without extra syntax.
url_icon.html:
{% include "icon.html" with icon=name %}
icon.html will have access to name since you're not using the only keyword when updating its context, so your code might appear to work at first ({% include %} documentation). However, it looks like your intention is to refer to it as icon.
Use the variable icon in instead of name
icon.html:
<img src="/static/images/{{ icon }}.png" />
Optional suggestion: Use Django's staticfiles system
Try using the {% static %} tag for your icon. This will help make deployment easier, especially if you use a separate CDN from your webserver. There's lots of literature on how to set up staticfiles for Django projects in production, it's a large topic, but you'll be able to approach it more easily if you use the {% static %} tag from the beginning.
Optional suggestion: Django's URL routing system
Your route in index.html is hard-coded to be "/". Django has a powerful URL referencing system to leverage. If you've defined the root URL / using Django too, you can refer to it by name. Docs: {% url %}, and for the back-end, reverse().

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.

Nested variables with dynamically generated URLs in Django

I'm trying to dynamically generate a URL based on a context variable (objecttype) passed into a template:
<a href="{% url 'wakemeup:edit_object' objecttype='school' objectid='new' %}">
Instead of objecttype='school', I want something like objecttype={{ objecttype }}.
I tried using the |add: operator and including {{ objecttype }} directly in the URL, but I keep getting parsing errors.

How to provide canonical URL with Django HttpResponseRedirect?

This question is very similar to one I just asked href: Can I get Google search results to use/display the final redirect url?, but now the question is specific to Django.
My site has webpage urls that use the following format:
www.mysite.com/id/pretty_title
The front page links to these pages, but the href actually contains some parameters:
www.mysite.com/id/?some_ugly_parameters_to_let_me_know_what_search_it_is_from
This then redirects to
www.mysite.com/id/pretty_title
which shows the page.
My issue is that Google's search results show the link to the page as the ugly url instead of the pretty redirected one.
What I have learned is that I need to provide a canonical link. But how can I do this when the ugly url page never really exists, at least not as one that I have written?
What happens server side is that the view of the ugly url does a redirect:
return HttpResponseRedirect(pretty_url)
I think this is the correct built template tag that you're looking for.
{{ request.build_absolute_uri }}
You can just put it as part of the HTML returned from the Django template, in the <head> section.
Do you have a base.html in your Django? You can setup a {% block %} as a placeholder for the canonical URL and then set that value in each individual page that {% extends base.html %}
base.html
<html>
<head>
<link rel="canonical" href="{% block canonical_url %}{% endblock %}">
</head>
...
A lot of these proposed solutions have issues if (1) you want your www subdomain to be the canonical one and (2) there are URL params in the request path.
I would actually propose to hard code it in the base template and append request.path.
<link rel="canonical" href="https://www.example.com{{ request.path }}">
If you do end up wanting to use build_absolute_uri, I would do it as follows in your view (or you could create a template function):
canonical_url = request.build_absolute_uri(request.path)
Calling build_absolute_uri() without an argument will call request.get_full_path() and append that to your domain. If a user finds your site via https://www.example.com/?param=123, your canonical URL will include that param.

Showing 'cancel' on login page to return user to where they were (using django.contrib.auth)

We are using the #login_required decorator so that users see a login page if they try to access a url for which they need to be authenticated.
We want to show a 'cancel' button on the login page, which should return the user to whichever page they were on when they tried to access the url (by clicking a link etc - we don't need to deal with them manually entering the url).
At the moment our login.html looks for a request parameter 'login_cancel_url' and if present uses that (otherwise the home page).
However, this means we have to manually pass this parameter (set to the url of the current page) whenever we show a link or button that leads to an 'authentication required' url.
Is there a more elegant way to do this?
Thanks, Martin
Well you can try get the referrer header from the request but as far as I am aware, it's browser dependent and is not very reliable so the way you are doing it is probably best. You could try make life easier by creating template tags to avoid having to rewrite the return URL manually.
You are easily able to get the current URL from django's request object on any page, so instead of setting it manually on the link, you could write a snippet of html:
link_to_login.html
<!-- You should probably get /login/ using the {% url ... %} template tag -->
<a href="/login/?login_cancel_url={{ request.path|urlencode }}">
Login Page</a>
and use the {% include "link_to_login.html"%} template tag.
Alternatively, If the text needs to be different depending on the link you can instead create an inclusion template tag:
templatetags/extra_auth_tags.py
#register.inclusion_tag('templates/extra_auth_tags/login_link.html')
def login_link(context, text=None):
return {
'text':text
}
templates/extra_auth_tags/login_link.html
<!-- You should probably get /login/ using the {% url ... %} template tag -->
<a href="/login/?login_cancel_url={{ request.path|urlencode }}">
{% if text %}
{{ text }}
{% else %}
Some Default Text
{% endif %}
</a>
and then call it in your templates as {% login_link text="Check you messages" %}. Be aware that keyword arguments for inclusion tags are only supported in the django dev version so you might need to write the template tag by hand.