How to mix Pug/Jade with Django conditionals and html element attributes? - django

I want to write Django conditionals for html attributes, like
<a {% if item.link %} href="{{ item.link }}", target="_blank", rel="noopener", aria-label="{{ item }}" {% endif %}>
--- Content ---
</a>
I am using pug/jade, so I can't put jade/pug syntax inside "Content" block, the compiler breaks. I would like to know if I can handle that in any way to no repeat the "Content" block.
I tried also, withouth success:
a({% if item.link %} href="{{ item.link }}", target="_blank", rel="noopener", aria-label="{{ item }}" {% endif %})
----Content---

I finally found a way to achieve this. Incredibly the solution is very simple and I felt a little dumb when I found it:
<a {% if item.link %} href="{{ item.link }}", target="_blank", rel="noopener", aria-label="{{ item }}" {% endif %}>
--- Content ---
</a>
Just need to put the --- Content --- block in the same indentation level as the plain html content.

Related

What is the DRY way to manage complex querystrings in django?

In my django project I have two options that use querystrings to define a kind of list being fetched, e.g:
Shopping
Chores
On top of that I also want to check which list has been selected by the user and make it appear bold in the UI. So
{% if 'shopping' in request.GET.list or not request.GET.list %}
<b>Shopping</b>
Chores
{% elif 'chores' in request.GET.list %}
Shopping
<b>Chores</b>
{% endif %}
What's really confusing me now, is in addition to Shopping and Chores I also want to have two sub-options that define the order of the list. New and Old, for instance. To me it seems like the only way of doing this is with another duplication of all the code.
{% if 'new' in request.GET.list %}
{% if 'shopping' in request.GET.list or not request.GET.list %}
<b>Shopping</b>
Chores
<b>New</b>
Old
{% elif 'chores' in request.GET.list %}
Shopping
<b>Chores</b>
<b>New</b>
Old
{% endif %}
{% elif 'old' in request.GET.list %}
{# ... #}
{% endif %}
I think you can already see how insane this becomes to manage and you would still need to do the same for the Old if statement. I really don't know what to do here because I can't see any other way to (1) Know what should be bold and not bold. And (2) Known whether each option should begin with a ? or &.
Regarding your first problem with having bold selected value, by the use a of a HTML class you can do the following instead for example.
In your css file (or style block in your html file):
.selected {font-weight: bold;}
So your html can now become somehing like,
<a class="{% if 'shopping' in request.GET.list or not request.GET.list %} selected{% endif %}" href="{% url 'index' %}?list=shopping">Shopping</a>
<a class="{% if 'chores' in request.GET.list %}selected{% endif %}" href="{% url 'index' %}?list=chores">Chores</a>
This way you dont have to write your html twice or more for each case.
As for your second issue, you can do something like below if you are using your 'new' and 'old' in your urls or html,
{% with 'new old bla' as list %}
{% for option in list.split %}
<a class="{% if 'shopping' in request.GET.list or not request.GET.list %} selected{% endif %}" href="{% url 'index' %}?list=shopping&option={{ option }}">Shopping</a>
<a class="{% if 'chores' in request.GET.list %}selected{% endif %}" href="{% url 'index' %}?list=chores&option={{ option }}">Chores</a>
{% endfor %}
{% endwith %}
Thats just an example of how you would use it, but this will save alot of code writing.
Hope this helps!
You could use a QueryDict for your query strings. That's what Django uses internally.
https://docs.djangoproject.com/en/2.1/ref/request-response/#django.http.QueryDict
But really, I would consider refactoring your code. Put routing logic in your urls.py and business logic in your view functions. Try to keep the template files as uncomplicated as possible.
Instead of /?list=shopping you can use a regular url: /list/shopping/, for example.

Django add link after slice

i have the following in my html template:
<h1><u>{{ post.title }}</u></h1>
<p>{{ post.content|slice:":1000"|linebreaksbr }}</p>
i want that after the slice to 1000 chars a href to the full article gets displayd.
e.g.:
<h1><u>{{ post.title }}</u></h1>
<p>{{ post.content|slice:":1000"|link:"... read on" href= url 'post_detail'|linebreaksbr }}</p>
any idea?
Well separate the text of the partial article from the link. Like:
<p>{{ post.content|slice:":1000"|linebreaksbr}}
read on</p>
Typically by splitting up problems in subproblems, the problem becomes easier to manage.
The {% url ... %} is probably with pk=post.pk or something similar, since otherwise it would link to the post_details, but without a specific post.
Alternatively, if you only want to show read on when the content is sliced, you can use an {% if ... %}:
<p>{{ post.content|slice:":1000"|linebreaksbr}}
{% if post.content|length > 1000 %}
read on
{% endif %}</p>

Conditionally add data-attributes in Jekyll

My basic YAML Front Matter for blog posts looks as:
layout: post
title: 'Crepes'
permalink: /crepes/
src: '/assets/images/crepes.jpg'
date: 2018-05-24 21:41:00
origin: http//...
ingredients:
- ingredient1: amount
- ingredient2: amount
Here is my index.html to display entries:
<ul>
{% for post in site.posts %}
<li data-title='{{ post.title }}' data-origin="{{ post.origin }}"
data-src="{{ post.src | prepend: relative_url}}"
data-content='{ "ingredients": {{ post.ingredients | jsonify }} }'>
<a href="{{ site.baseurl }}{{ post.url }}">
<img src="{{ post.src | prepend: relative_url }}" alt={{ post.title }}/>
</a>
</li>
{% endfor %}
</ul>
The problem is:
Some posts are supposed to have no origin value, like origin:. And I am looking for a way to add data-origin attribute only if it's value specified in YAML Front Matter.
Liquid give following option:
{% if condition %}
<li>....</li>
{% endif %}
Is there any way to use it inside of html tag? In my case I expect something like this:
{% for post in site.posts %}
<li
{% if post.origin has value %}
data-origin="{{ post.origin }}"
{% endif %}">
</li>
{% endfor %}
Here I see four cases :
post.origin is not present in front matter :
post.origin == null
post.origin is present in front matter, but not set (post.origin:)
=> post.origin == null`
post.origin is present in front matter, but set to empty string (post.origin: "")
=> post.origin == ""
post.origin is present in front matter, and set to valid string (post.origin: "toto")
=> post.origin == "toto"
Results are conform to Truthy and falsy Liquid documentation.
From there, using logical liquid operators, we can build a condition like :
<li
{% if post.origin and post.origin != "" %}
data-origin="{{ post.origin }}"{% endif %}>
</li>
Note that post.origin means post.origin != null.

NoReverseMatch when rendering page

I seem to know where the issue is located since I can get around it, but for getting around it I have to sacrifice a function I really want to keep.
Here is the relevant code in the non-working state:
{% if sections %}
{% for item in sections %}
<a class="sections" href="{% url 'sections:generate' item.section.slug %}">{{ item.section.title }}</a>
{% for subsection in item.subsections %}
<p>{{ subsection.title }}</p>
{% endfor %}
{% endfor %}
{% else %}
<p>Error retrieving sections or no sections found</p>
{% endif %}
The problem part above is in the link tag. Let me explain by showing the related view.py:
def index(request):
sections = Section.objects.all()
context = {
'sections': [],
}
for section in sections:
context.get("sections").append(
{
'section': section,
'subsections': get_subsections(section),
}
)
return render(request=request, template_name='index.html', context=context)
So, 'sections' is an iterable list of items, containing for every items a dictionary with two entries. One, 'section' and one 'subsection'. There are multiple subsections for every section, this is what I really want to accomplish.
Ordinarily, when not bothering with subsections and simply iterating over a list of sections works fine. The template code for that would look something like:
{% for section in sections %}
{{ section.title }}
{% endfor %}
NOTE! The code above works just fine! But as soon as I add 'sections' as a list of dictionaries and have to reference the slug by item.section.slug the pages stop rendering.
Please advise.
Try using tuples:
View:
context['sections'] = [(section, tuple(get_subsections(section))) for section in sections]
Template:
{% for section, subsections in sections %}
<a class="sections" href="{% url 'sections:generate' section.slug %}">{{ section.title }}</a>
{% for subsection in subsections %}
<p>{{ subsection.title }}</p>
{% endfor %}
{% endfor %}

Django variable substitution in the include template tag

I have an internationalized Django 1.3 site and want to do this:
{% include "snippets/button.html" with button_text=_("Logout {{ user.username }} now") %}
And snippets/button.html looks like this:
<button
type="{{ button_type|default:_('submit') %}"
class="all_my special classes"
{% if button_title %} title="{{ button_title }}"{% endif %}>
<span class=ui-button-text>{{ button_text|default:_("Submit") }}</span>
</button>
The only way I can see to do this is something like:
{% include "snippets/button.html" with button_text="Logout "|add:user.username|add:" now" %}
But this is not acceptable as the strings to translate need to include where the variable substitution will occur. I have seen Interpolate Django template include variable but that doesn't cover this usage.
I think your best bet in this case is to add the already translated string to your context.
In your views.py:
...
'button_text': _("Logout {} now").format(user.username),
...
Then in your template:
{% include "snippets/button.html" with button_text=button_text %}
Something like this may let you go on:
{% blocktrans with value|filter as myvar %}
This will have {{ myvar }} inside.
{% endblocktrans %}
from here http://www.djangobook.com/en/1.0/chapter18/
It should work with includes, but I haven't tested.