Liquid: Capture String in a space Following a "trigger string" possible? - arrays

Instead of doing this below in liquid when I might not even know all the possible colors that could exist, could I somehow just capture the full next row following "Color:" so that "Color:" is the triggertag that starts the capture and next row break is the trigger that decides when the capturing should stop?
And could I also use another word as the trigger of the end capture, for example if I know that I always want to capture what is between the only <strong> and </strong> tag in a description?
{% if product.description contains 'Color:' %}
{% if product.description contains 'Color: Red'%}{% assign TheColor = "Red" %}{% endif %}
{% if product.description contains 'Color: Yellow'%}{% assign TheColor = "Yellow" %}{% endif %}
{% if product.description contains 'Color: Ocean Blue'%}{% assign TheColor = "Ocean Blue" %}{% endif %}
{% if product.description contains 'Color: Light Blue'%}{% assign TheColor = "Ocean Blue" %}{% endif %}
{% if product.description contains 'Color: Blue'%}{% assign TheColor = "Blue" %}{% endif %}
{% if product.description contains 'Color: Black & white'%}{% assign TheColor = "Black & white" %}{% endif %}
{% endif %}
I've been googling for hours for something like this, I know I did it somehow in Asp Classic 10 years ago with a long code, but I figure it should be super simple in Liquid?
I don't have formal liquid education (which I probably share with many others who find this through searches) so a simple example in code rather than a "tech hint" or "clue" would be awesome.
Thank you!

Here's a bit of a hacky way to get just the colour, though it doesn't feel super reliable:
{% assign color = product.description | split: "Color: " %}
{{ color | last }}
This splits the description into an array. Everything before Color:is the first element, and everything after Color: is the second element. In our output we just print the second element.
This won't work right if there's anything else after the color declaration in your product description.

Related

How can I find out if my variable is an object or an array with twig?

I try to find out if my variable is an object or an array:
{% if variable is iterable %}It is an array{% else %}it is an object{% endif %}
But in cases I get the result:
It is an array
You are correct, the twig iterable test has shortcomings, since objects can be iterable as well. PHP has handy functions like is_array and is_object, however, it is not possible to access regular PHP function in Twig directly. So, we need to write a Twig extension/Test, i.e. add a new Twig_SimpleTest to check if an item is_array. You can add this test to your app configuration after the general twig bootstrap.
$isArray= new Twig_SimpleTest('array', function ($value) {
return is_array($value);
});
$twig->addTest($isArray);
and simply us it like this:
{% if var is array%} It is an array
{% else %} It is an object{% endif %}

webapp2 routes for locale in URL

The webapp2 i18n documentation has an example of specifying the locale in a parameter, e.g.:
www.example.com?locale=en_US
but Google search console says that this is not recommended.
I'd like to instead put the locale in the URL like this:
www.example.com
www.example.com/about
www.example.com/contact
www.example.com/fr
www.example.com/fr/about
www.example.com/fr/contact
What is a good way of setting up your webapp2 routes and passing the locale as a parameter to your handlers?
If you want to try the way I do it: Set a regex (app = webapp2.WSGIApplication([('/([^/]+)/?([^/]*)', RegionSearch)], config=settings.w2config, debug=settings.DEBUG) and then "pass on" the parameter to the template where you can set the locate arbitrarily for many different locales, timezones and currencies e.g.
{% if request.... == "..." %} # depend on values in the request
{% set currency = "SEK" %}
{% set format = "sv_SE" %}
{% set timezoneinfo = 'Europe/Stockholm' %}
{% set locale = "se" %}
{% endif %}
I ended up using a variation of Dj Dac's answer. I replace each route with two routes like this:
Route(r'/page', views.PageHandler),
Route(r'/<locale:\w\w>/page', views.PageHandler),
The route without the locale gives the default and is also used for the x-default hreflang tag.

iterating through a Django model field produces unwanted format

Python3.4 Django1.9 Noob here... :)
I am trying to loop through a Django field but am not getting the desired results, here's the picture:
the models field "info" can hold strings and in some cases python lists. My issue in this case is when it's a list and I have to iterate through it...
e.g.:
say the "info" field has something like this: ['2016-02-23', '2016-03-01'] and I try to loop through it on the Django1.9 template like this:
{% for i in dates %} {{i}}<br /> {% endfor %}
I expect to see something like this:
2016-02-23
2016-03-01
instead I get this:
[
'
2
0
1
6
-
0
2
-
2
3
'
,
'
2
0
1
6
-
0
3
-
0
1
'
]
which makes me think the mySQL field holding the data is fooling me into thinking this is a python list... my ability to change the format of the database field are limited... any help would be appreciated!
models.py
class Events(....
info = models.CharField(max_length=150, blank=True)
views.py
dates_list = []
obj_dates = Events.objects.filter(id=id)
for i in obj_dates:
dates_list.append(i.info)
context = {"dates": dates_list)
Django 1.9 template
{% for i in dates %} {{i}} {% endfor %}
just looking at your code
obj_dates = Events.objects.filter(id=id)
is only going to get you one entry (as you are filtering by id) - you are returning a queryset with only one object.
When you use:
for i in obj_dates:
dates_list.append(i.info)
you are appending a string "['2016-02-23', '2016-03-01']"
to dates_list. That is to say that dates_list is just a list containing a single string - it appears to be a list containing a list but it is a list containing a string.
in python strings are iterable, so the template is iterating through one character in the string at a time, thus returning you
[
'
2
...
Solutions
A. The hacky way
dates_list.append(list(i.info))
that will convert that string "['2016-02-23', '2016-03-01']" into a list
B. a more django-ish approach
Ask yourself can you store dates in a better fashion that as text in a charfield?
One way to do it is to use a dateField then use m2m so you can store multiple dates.
class Events(models.Model)
info = models.CharField(max_length=150, blank=True)
dates = models.ManyToManyField(Dates, related_name='events', blank=True)
class Dates(models.Model)
date = models.DateField(auto_now=False, auto_now_add=False)
Thanks to luke_aus for the help!
I also found something that could work in some cases...
If you see yourself in a situation having to unpack or loop through a Python list stored in a CharField, try this... it worked very well in my case...
Views.py
import ast
date_list = []
for i in obj:
l = {
'dates': ast.literal_eval(i.info), # i.info is a CharField containing a python list
}
dates_list.append(l)
Template
{% for d in dates %}
{{d}}<br>
{% endfor %}
2016-02-23
2016-03-01

Ansible: Use array to create a variable

To deploy the ldap.conf with Ansible, I have to create one variable from an array, to use in a template ldap.conf.j2:
nss_base_group {{ ldap_base_group }}
The variable array:
---
ldap_groups: [ 'ORACLE', 'MY_SQL', 'POSTGR' ]
This has to result in one parameter, enhanced with al lot of static characters:
ldap_base_group:"dc=foo,dc=com?sub?(&(|(memberof:1.2.654.123456.1.5.2468:=cn=ORACLE,ou=Groups,dc=foo,dc=com)(memberof:1.2.654.123456.1.5.2468:=cn=MY_SQL,ou=Groups,dc=foo,dc=com)(memberof:1.2.654.123456.1.5.2468:=cn=POSTGR,ou=Groups,dc=foo,dc=com))(!(userAccountControl:1.2.654.123456.1.5.654:=2)))"
This is the same parameter made readable (not usable because of newlines, spaces etc):
ldap_base_group: "dc=foo,dc=com?sub?
(&
(|
(memberof:1.2.654.123456.1.5.2468:=cn=ORACLE,ou=Groups,dc=foo,dc=com)
(memberof:1.2.654.123456.1.5.2468:=cn=MY_SQL,ou=Groups,dc=foo,dc=com)
(memberof:1.2.654.123456.1.5.2468:=cn=POSTGR,ou=Groups,dc=foo,dc=com)
)
(!
(userAccountControl:1.2.654.123456.1.5.654:=2)
)
)"
Does anyone has found a nice solution to do this in Ansible? Maybe there is an other way to do this, I am eager to know alternatives too.
If you template this you should be able to do something along these lines:
ldap_base_group: "dc=foo,dc=com?sub?
(&
(|
{% for group in ldap_groups %}
(memberof:1.2.654.123456.1.5.2468:=cn={{ group }},ou=Groups,dc=foo,dc=com)
{% endfor %}
)
(!
(userAccountControl:1.2.654.123456.1.5.654:=2)
)
)"
If you need everything in a single line then just flattening this out should work fine.

The equivalent of this loop in Jinja

I would like to know how can I perform this loop in Jinja :
for r,s in (v,t):
#Do something
When I try to write something similar in Jinja(Flask), I had an error :
ValueError: too many values to unpack
v and t are lists of dicts .
Found : In jinja I should use zipped
{% for s, t in zipped %}
#do something
{% endfor %}
where zipped = zip (s,t)

Resources