webapp2 routes for locale in URL - google-app-engine

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.

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 %}

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)

How to get length of (or count) of datastore entities through a reference collection definition in google datastore from client side

I have 1 to many datastore relationship between 2 Entities (google datastore) --- i.e. an instance in the Restaurant_Table can have many reviews from the Review_Table - as labeled by collection "restaurant_reviews"
As I spin through each restaurant (in a loop) to a list each of them in my template through jinja, I want to display the number or count of reviews there are for a single restaurant. All restaurants are passed from server in the form of a query from the datastore in variable restaurants as shown in the jinja2 logic in my template.
I'm getting an error that the query object TypeError: object of type 'Query' has no len(). Any other ideas on how to get the # of reviews for a single restaurant?? help!
{% for each in restaurants %}
<script>
var html_output = "";
var review_count ={{each.restaurant_reviews|length}};
...
{% endfor %}
DATASTORE ENTITY definition is:
class Review_Table(db.Model):
date_submission = db.DateTimeProperty(required=True, indexed=True)
course_id = db.ReferenceProperty(Restaurant_Table,
indexed=True, collection_name='restaurant_reviews')
To get the number of entities represented by the query you can use the count method:
db.Query(Kind).count()
You can't do this within a jinja template -- you would need to build your output in your handler, and then render to your template.
However, as the docs say the .count() method "is faster by a constant factor than actually retrieving all of the results, but the running time still scales linearly with the sum of offset + limit." Meaning, this could get really, really slow if you get a large number of restaurants/ reviews.
A better option, in my opinion, would be to add an extra property to your Restaurants model "num_reviews", which your handler would update every time a new review is added -- making very slightly more expensive/slower writes would become hugely cheaper/faster reads because no extra querying would have to be done.
Performance could be an issue, but this will accomplish the task:
var review_count = {% for n in restaurant_reviews %}{% if loop.index == 1 %}{{ loop.length }}{% endif %}{% endfor %};

Resources