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
Related
I've started using Google Cloud Deployment recently, having come from AWS CloudFormation (and Terraform alongside) and I'm really struggling to use Jinja in dynamic ways that I do so simplistically in the others.
My current issue is that my deployment is entirely dynamic based on some user input, and so in AWS CF and Terraform (which points at both AWS and GCP) I use maps to get settings determined by a previous choice. The following is an example from Terraform:
variable "Cluster_Instance_Map" {
type = map
default = {
"C1" = "Single-Node : 0 : A : B"
"C2" = "Multi-Node : 2 : Q : R"
"C3" = "Multi-Node : 4 : X : Y"
"C4" = "Multi-Node : 8 : S : T"
...
}
}
And then I would, for example, grab the first value for the respective row by using the Cluster_Config_Choice variable chosen from 'C1, C2, C3, C4' by a user previously as follows:
split ( " : ", var.Cluster_Instance_Map[ var.Cluster_Config_Choice ] ) [0]
Thus far, I've really struggled to re-create this type of variable in Jinja for GCP. I'm new to GCP in general, but also Jinja, and what I find online is, for the most part, confusing me more than anything, and so any help with this is muchly appreciated!
--- Edit ---
As per request, I will give some detail into what I've done with Jinja thus far, although it sadly isn't too much. My initial idea is via the use of LIST and SPLIT. I figure I could do something like the following:
{% set list_example = ({ "A" : "1 ; 2 ; 3", "B" : "4 ; 5 ; 6" }) %}
{{ list_example [ user_input_variable ].split(';')[1] }}
And the second line would then return, "5" if the user selected B, for example. I did make that code up, though (second line) so it doesn't work for syntax errors (100% expected) but I don't know if it's even close.
Is a LIST and SPLIT the way to go? Or are there MAP-like functions available that I am missing out on..
I also don't know how to put my SET function across multiple lines without erroring, so sorry for the mess above. Though I assume Google can tell me that when I'm not busy! >.>
Hope this helps clarify things.
After going around in circles, and learning very minimal in the process, I've actually realised that my answer was what I had already tried... The code I posted above saying doesn't work, works - Though it turns out there were a multitude of other reasons it didn't, but not related directly to itself.
And so, my answer to re-create what I have as a 'map' in Terraform/AWS CF is as follows:
{% set Cluster_Instance_Map = ({
"C1" : "Single-Node : 0 : A : B",
"C2" : "Multi-Node : 2 : Q : R",
"C3" : "Multi-Node : 4 : X : Y",
"C4" : "Multi-Node : 8 : S : T",
...
}) %}
{% set user_input_variable = "C3" %}
{{ Cluster_Instance_Map [ user_input_variable ].split(':')[1] }}
And the final piece would return the number 4, in that case. My code is also across multiple lines, so it's much easier to read now as well - This also was an issue unrelated (as mentioned, I'm entirely new to Google and Jinja, so lessons learned).
I must say, though, the documentation for Google Cloud really is terrible in comparison to others. Very easy to loose yourself. So even though the above doesn't really need an answer, figure best to put this here just in case others have a similar question.
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.
I have the following code:
#set ($recsList = [$entity1,$entity2,entity3,entity4])
#foreach($article in $recsList)
<li>
Entity # $velocityCount in $article.id<br/>
</li>
#end
In my recsList only entity1 and 2 has a value, 3 and 4 are empty. Now, the above isn't working because entity3 and 4 in my recsList doesn't have a value. If I limit recsList to only entity1 and 2, then it is working just fine.
I've tried solving it by creating a new array only with products that has .id set:
#set ($displayRecs=[])
#foreach($article in $recsList)
#if($article.id!="")
$displayRecs.add($displayRecs.size(), $article)
#end
#end
But it still requires that recsList only contains the entity that has value listed.
Is there any way I can get it to work when having entity listed in recsList that doesn't have values?
You can use the quiet reference notation:
#set ($recsList = ["$!entity1","$!entity2","$!entity3","$!entity4"])
#foreach($article in $recsList)
<li>
Entity # $velocityCount in $article.id<br/>
</li>
#end
This way, missing values will appear as empty strings.
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 %};
I am doing development on python and GAE,
When I try to use ProtoRPC for web service, I cannot find a way to let my request contain a json format data in message. example like this:
request format:
{"owner_id":"some id","jsondata":[{"name":"peter","dob":"1911-1-1","aaa":"sth str","xxx":sth int}, {"name":...}, ...]}'
python:
class some_function_name(messages.Message):
owner_id = messages.StringField(1, required=True)
jsondata = messages.StringField(2, required=True) #is there a json field instead of StringField?
any other suggestion?
What you'd probably want to do here is use a MessageField. You can define your nested message above or within you class definition and use that as the first parameter to the field definition. For example:
class Person(Message):
name = StringField(1)
dob = StringField(2)
class ClassRoom(Message):
teacher = MessageField(Person, 1)
students = MessageField(Person, 2, repeated=True)
Alternatively:
class ClassRoom(Message):
class Person(Message):
...
...
That will work too.
Unfortunately, if you want to store arbitrary JSON, as in any kind of JSON data without knowing ahead of time, that will not work. All fields must be predefined ahead of time.
I hope that it's still helpful to you to use MessageField.