string in list of list - python

I have two lists like:
DevInDB = ['Dev1','Dev2','Dev3']
and
DevInMesh = [['Dev1',0,0],['Dev2',1,1]]
I want to know if, for any DevInDB string, there is the same string in DevInMesh.
I wrote this code that works (in python)
for dev in DevInDB:
if any(dev in DevMesh for DevMesh in DevInMesh ):
print(dev)
else:
print('no')
I try to ust this code in a HTML file using jinja, but the 'any' function doesn't work. How can I do it?

You need to compute this before sending it to jinja.
Ex:
DevInDB = ['Dev1','Dev2','Dev3']
DevInMesh = [['Dev1',0,0],['Dev2',1,1]]
DevInMesh = {k for k, *_ in DevInMesh}
DevInDB = [(i, i in DevInMesh) for i in DevInDB]
print(DevInDB)

I've done it this way:
{% for DevDB in DevInDB %}
{% set ns = namespace(foo=false) %}
{% for DevMesh in DevInMesh %}
{% if DevMesh [0] == DevDB %}
{% set ns.foo = True %}
{% endif %}
{% endfor %}
and later on:
{% if ns.foo %}
{% else %}
{% endif %}

You can replace the any expression with the simple list comprehension where non-empty list will be True:
[1 for DevMesh in DevInMesh if dev in DevMesh]
Or better is to remove the computational part from template because a template is the view part that works on presentation level of the context, such that all pre-computed expressions should be stored in the context and only printed in the template.

Related

Get element of list by variable in Django template

I have line of code in Django template:
<h4>{{ totals.date.weekday }}</h4>
Totals is the Python list, how do i get item of this list by index stored in date.weekday?
This would look in Python like this:
totals[date.weekday]
Creating another variable, which stores date.weekday doesn't work
UPD:
I found a solution:
Just added element of totals list to template context in render
For example:
# ...
return render(request, 'template.html', context={'date_total'=totals[date.weekday()]})
You can access the array directly using
{{ totals.0.date.weekday}} where the 0 is the position that you want.
Also if you want to print all the elements in total you will need a for loop such as:
{% for d in totals %}
{{ d }}
{% endfor %}
about sorting, you can use the pipe order_by but I recommend you to pass the list already ordered from the views
You have to run the "for loop" for this.
{% with counts = 0 %}
{% while counts < totals.count %}
{% if counts == date.weekday %}
<h4>total.counts</h4>
{% endif %}
{% counts += 1 %}
{% endfor %}
I did not get your question completely but i think it might help.

How to change value of variable in django template?

I want to declare a flag variable in django template and the change it if some thing happened.
But when I change value of variable by custom tag it is declared a new variable and doesn't change.
for example my template tag and django template is:
template tag:
#register.simple_tag
def update_variable(value):
return value
html:
{% with True as flag %}
<h1>1: {{ flag }}</h1>
{% for e in events %}
{% if e.title == '***' %}
{% update_variable False as flag %}
<h1>2: {{ flag }}</h1>
{% endif %}
{% endfor %}
<h1>3: {{ flag }}</h1>
{% endwith %}
and result is:
1: True
2: False
3: True
But the end result should be False! How to do this?
I find a solution for it. for check all element of list we can use custom filter an do some thing there:
html:
//load custom filter
{% load my_filters %}
{% if "anything we want"|is_in:events.all %}
//do some thing...
{% else %}
//do some thing...
{% end if%}
custom filter in my_filter file:
register = template.Library()
def is_in(case, list):
for element in list:
if element.time_span == case:
return True
return False
register.filter(is_in)

Jinja2: Compare items in one list to items in another list

I have a list of topics:
list1 = [topic1, topic2, topic3, topic4, topic5, topic6]
I would like to check another list against this list:
list2 = [topic2, topic4, topic6]
something like this:
{% if list2.items in list1 %}
where each item from list2 is checked for in list1. if all or any of the items from list2 are in list 1 then it's True. I figured this would be simple but I can't seam to find anything helpful about this.
Full example:
{% set list1 = [topic2, topic4, topic6] %}
{% for post in posts %}
{% set list2 = [topic1, topic2, topic3, topic4, topic5, topic6] %}
{% for topic in list2 %}
{% if topic in list1 %}
{# output of post list based on conditions #}
{% endif %}
{% endfor %}
{% endfor %}
** I am working in a cms with out server side access so I only have the templating language to work with.
Just create a custom filter:
def intersect(a, b):
return set(a).intersection(b)
env.filters['intersect'] = intersect
And then use it as any other filter:
{% if list1 | intersect(list2) %}
hello
{% else %}
world
{% endif%}
This is how it's done in Ansible.
I am not aware of any Jinja2 built-in tests that can do this, but it's easy to add your own.
Let's say you have a template like this in a file called template.j2:
Is l1 in l2: {% if l1 is subsetof(l2) %}yes{% else %}no{% endif %}
You can then (in the same directory for this example), have a Python script that adds this check:
import jinja2
def subsetof(s1, s2):
return set(s1).issubset(set(s2))
loader = jinja2.FileSystemLoader(".")
env = jinja2.Environment(loader=loader)
env.tests["subsetof"] = subsetof
template = env.get_template("template.j2")
print(template.render(l1=[1, 2], l2=[1, 2, 3]))
Note that the first argument of the test function is passed before the is clause in the template, while the second argument is passed within the brackets.
This should print:
Is l1 in l2: yes
Take a look at how to define custom tests here

Django model query tune up

I want to reduce the number of template filter calls in my_filter_function(). Because It's used inside two for-loops inside a template. Please see below for my code setup.
class ModelA(models.model):
models.ForeignKey(OtherModel1)
class ModelB(models.model):
models.ForeignKey(OtherModel2)
class ModelC(models.Model):
a = models.ForeignKey(ModelA)
b = models.ForeignKey(ModelB)
def my_views(request):
return render(request, 'my_template.html', {
'a_list': ModelA.objects.all(),
'b_list': ModelB.objects.all(),
})
and in my template, I have
{% for a in a_list %}
{% for b in b_list %}
{% with b|my_filter_function:a as my_val %}
Val: {{my_val}}
{% endwith %}
{% endfor %}
{% endfor %}
the above template will will call the my_filter_function filter function, I need to find another way to reduce the number of my_filter_function function calls, because the filter function is accessing the DBs several thousand times per template now.
#register.filter
def my_filter_function:(b, a):
z = ModelC.objects.filter(a=a, b=b)
if z.count() > 0:
return "OK"
else:
return "Not OK"
Here's a faster alternative.
Fetch all the ids of A and B in C at once:
z = ModelC.objects.values_list('a_id', 'b_id')
a_related, b_related = zip(*z) # split into a and b ids
Pass these to your context:
def my_views(request):
return render(request, 'my_template.html', {
'a_list': ModelA.objects.all(),
'b_list': ModelB.objects.all(),
'a_related': a_related,
'b_related': b_related,
})
And then use if...in in your template. The custom template filter can now be discarded:
{% for a in a_list %}
{% for b in b_list %}
{% if a.id in a_related and b.id in b_related %}
"OK"
{% else %}
"Not ok"
{% endif %}
{% endfor %}
{% endfor %}
That replaces all the multiple queries in your filter with just one.

How to get Substr of values

Hi I have the following query in my views.py
m = Request.objects.filter(Q(type__icontains='4'), Q(wt__in =['giga','mega']))
context['all_items'] = m.values('type1').order_by('type1')
Its giving values sasoo, masoo, pisoo, kusoo etc.
How can I implement the Django Substr in this case so that my html will display values as sa, ma, pi, ku, ..
You can annotate the model
from django.db.models.functions import Substr
m = Request.objects.filter(Q(type__icontains='4'), Q(wt__in =['giga','mega']))
context['all_items'] = m.annotate(mysubstring=Substr('type1',1,2)).order_by('type1')
In template:
{% for obj in all_items %}
{# Use obj.mysubstring #}
{% endfor %}
You can use slice filter in your template:
{% for item in all_items %}
{{ item.type1|slice:":2" }}
{% endfor %}
One liner
context['all_items'] = [i[:2] for i in context['all_items']]

Categories