Django regroup by upper and lower case - python

I have a project in django, where I have to display clients in alphabetical order but names of companies can start from upper or lower case.
For now my solution below display names starts from lower case in one section and name starts from the same letter, but uppercase in another section.
{% regroup clients by title.0 as clients_list %}
{% for client in clients_list %}
{{ client.grouper }}
{% for item in client.list %}
{% if item.client_link %}
{{ item.title }}
{% else %}
{{ item.title }}
{% endif %}
{% endfor %}
{% endfor %}
How to display name starts from upper and lower case under one section?

Using Django built-in template filter called title
{{ item.title|title }} {% else %} {{ item.title|title }}

Related

Django: Nested Loop In Template

category = ['cat1','cat2','cat3']
inventory = CurrentInventory.objects.all()
for cats in categories
inventorybycat = inventory.filter(category =cats)
setofinventories.append(inventorybycat)
dictofstuff = [zip(setofinventories,categories)]
context = {
'setofinventories':setofinventories
'category':category
'dictofstuff':dictofstuff
}
In views.py above this loop creates a list of objects per each category.
In the template below this loop prints a filtered object list per every item in the category list.
{% for inventory in setofinventories%}
{% for item in inventory %}
{{ item.category }}
{{ item.productName }}
{% endfor %}
{% endfor %}
The only thing I am missing is I do not now how to reference the category in the template. I pass the whole list in context, but {{category{{forloop.counter}}}} is not a valid statement.
I would either like to use zip(category,setofinventories) to pass these two items together,
or create a category model, filter by that model and then I can reference that model by item?
If I zip these items dictofstuff = [zip(setofinventories,categories)]
How do I reference the category in the template?
{% for inventory,categories in dictofstuff %}
{% for inventory in setofinventories%}
{% for item in inventory %}
{{ item.quantity }}
{{ item.productName }}
{% endfor %}
{% endfor %}
{% endfor %}
Returns Error: "Need 2 values to unpack in for loop: got 1."
If i right understand you, you want to print category only one time.
In your case:
{% for inventory in setofinventories%}
{% ifchanged inventory.category %}
{{ inventory.category }}
{% endifchanged %}
{% for item in inventory %}
{{ item.quantity }}
{{ item.productName }}
{% endfor %}
{% endfor %}
i use ifchanged, more here:
https://docs.djangoproject.com/en/4.1/ref/templates/builtins/#ifchanged
in views i zipped this to a *listofstuff. Forgive the nomenclature.
dictofstuff = [zip(categories,setofinventories)]
in template. Again, forgive bad nomenclature. I should go back and rename these but it works.
{% for category in dictofstuff %}
{% for item in category %}
{{item.0}}
{% for stuff in item %}
{% for thing in stuff %}
{{thing.productId}}{{thing.productName}}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}

How to pass template variable to slice filter in Django templates

I'm trying to slice loop in django template with variable
USUAL WAY
{% for article in module.module_article_key.module_article_category.article_category_key.all|slice:":2" %}
{{ article.article_title }}
{% endfor %}
WHAT NEEDS
{% for article in module.module_article_key.module_article_category.article_category_key.all|slice:":module.module_article_key.module_article_count" %}
{{ article.article_title }}
{% endfor %}
so we have working variable {{ module.module_article_key.module_article_count }}
normaly this variable gives integer value stored for this module, however wen i use it to slice loop - nothing happens
You need to cast module_article_count to string first then making articleSlice via nested {% with %} and use the resulting template variable in slice filter as follow:
{% with articleCount=module.module_article_key.module_article_count|stringformat:"s" %}
{% with articleSlice=":"|add:articleCount %}
{% for article in module.module_article_key.module_article_category.article_category_key.all|slice:articleSlice %}
{{ article.article_title }}
{% endfor %}
{% endwith %}
{% endwith %}

Setting variable in Jinja for loop doesn't persist between iterations

I want to loop over a list of objects and count how many objects meet a requirement. I based my code off other examples I'd found, but it doesn't work, the count is always 0 after the loop.
For each house, I want to loop over each room and count how many rooms have a bed. I want to output that then reset the count for the next house.
{% for house in city %}
{% set count = 0 %}
<div>{{ house.address }} has {{ count }} beds in it rooms.</div>
{% for room in house %}
{% if room.has_bed == True %}{% set count = count + 1 %}{% endif %}
{% endfor %}
{% endfor %}
Jinja 2.10 introduces the namespace object to handle assignment and comparison in loops.
{% set ns = namespace(beds=0) %}
{% for room in house %}
{% if room.has_bed %}
{% set ns.beds = ns.beds + 1 %}
{% endif %}
{% endfor %}
{{ house.address }} has {{ ns.beds }} beds.
Normally, set does not handle attributes, which is why the old answers mutate objects with methods instead. namespace has been special cased so setting attributes does work.
The reason the original counter didn't work is because of Jinja's scope rules. Unlike Python, most blocks are new scopes. set always defines a local variable, except in this new special case of namespace.attribute.
In this specific case, you can accomplish what you want with filters.
{% set beds = house.rooms|selectattr('has_bed')|length %}
{{ house.address }} has {{ beds }} beds.
However, there are cases where storing information across scopes is needed. For example, if you wanted to output some information in addition to incrementing the counter, it would make sense to use a namespace.
For Jinja 2.9, the scope behavior was fixed, invalidating code that worked in previous versions. The incremented value of count only lives within the scope of the loop. Their example involves setting variables, but the concept is the same:
Please keep in mind that it is not possible to set variables inside a block and have them show up outside of it. This also applies to loops. The only exception to that rule are if statements which do not introduce a scope. As a result the following template is not going to do what you might expect:
{% set iterated = false %}
{% for item in seq %}
{{ item }}
{% set iterated = true %}
{% endfor %}
{% if not iterated %} did not iterate {% endif %}
It is not possible with Jinja syntax to do this.
You will need to do a hacky-ish workaround in order to track count across iterations. Set a list, append to it, then count its length.
{% for house in city %}
{% set room_count = [] %}
{% for room in house %}
{% if room.has_bed %}
{% if room_count.append(1) %}{% endif %}
{% endif %}
{% endfor %}
<div>{{ house.address }} has {{ room_count|length }} beds.</div>
{% endfor %}
For Jinja <= 2.8, the code you've shown does work. However, this was due to incorrect behavior in Jinja's scope rules, which was fixed in 2.9.
{% for house in city %}
{% set count = 0 %}
{% for room in house %}
{% if room.has_bed %}
{% set count = count + 1 %}
{% endif %}
{% endfor %}
<div>{{ house.address }} has {{ count }} beds.</div>
{% endfor %}

How to print spaces from inside a variable in jinja2

I am trying to print a variable number of spaces stored in a variable in jinja2, but jinja is escaping the contents of the variable. So when I store &nbsp in the variable it gets expanded to &nbsp thus printing the characters &nbsp on the page instead of the spaces.
Here is my code:
{% macro show_message(parent_id,count) %}
{% set clist = get_message(post.id,parent_id) %}
{% set countr = count + 1 %}
{% set prefix = '-'*countr %}
{% set prefix2 = "&nbsp"*countr %}
{% if clist is defined %}
{% for c in clist %}
{{ prefix2 }} Author: {{ get_author(c.user_id) }} <br/>
{{ prefix }}
{{ c.message }}
<br/><br/>
{{ show_message(c.id,countr) }}
{% endfor %}
{% endif %}
{% endmacro %}
Does anyone have a clue how to make this work?
Thanks :)
I tried Blender's way with
{{ " "|safe*10 }}
it'll generate 10 spaces
Mark it as safe with the |safe filter to prevent auto-escaping:
{{ prefix2|safe }}
You also need to include the semicolon at the end of each entity:
{% set prefix2 = " "*countr %}
^

How to output a comma delimited list in jinja python template?

If I have a list of users say ["Sam", "Bob", "Joe"], I want to do something where I can output in my jinja template file:
{% for user in userlist %}
{{ user }}
{% if !loop.last %}
,
{% endif %}
{% endfor %}
I want to make the output template be:
Sam, Bob, Joe
I tried the above code to check if it was on the last iteration of the loop and if not, then don't insert a comma, but it does not work. How do I do this?
You want your if check to be:
{% if not loop.last %}
,
{% endif %}
Note that you can also shorten the code by using If Expression:
{{ ", " if not loop.last else "" }}
You could also use the builtin join filter like this:
{{ users|join(', ') }}
And using the joiner from https://jinja.palletsprojects.com/templates/#joiner
{% set comma = joiner(",") %}
{% for user in userlist %}
{{ comma() }}{{ user }}
{% endfor %}
It's made for this exact purpose. Normally a join or a check of forloop.last would suffice for a single list, but for multiple groups of things it's useful.
A more complex example on why you would use it.
{% set pipe = joiner("|") %}
{% if categories %} {{ pipe() }}
Categories: {{ categories|join(", ") }}
{% endif %}
{% if author %} {{ pipe() }}
Author: {{ author() }}
{% endif %}
{% if can_edit %} {{ pipe() }}
Edit
{% endif %}

Categories