I have this in the Google App Engine python code,
class ABC(db.Model):
StringA = db.StringProperty()
abcs = ABC.all()
template_values = {'abcs': abcs,}
path = os.path.join(os.path.dirname(__file__), 'index.html')
self.response.out.write(template.render(path, template_values))
and this in the index.html,
<script type="text/javascript">
{% for abc in abcs %}
var id = "{{ abc.ID }}"; // needed the entity ID, the abc.ID doesn't show??
{% endfor %}
</script>
What was the right keyword to use for the entity ID, the abc.ID??
Thanks in advance.
{{abc.key.id}}, assuming you're using Django templates. The ID isn't a property of the object, it's a part of the object's Key; in a Django template (which is what you're using if you're using google.appengine.ext.webapp.template), this is the equivalent to abc.key().id() in Python code.
Note that not all entities have an ID at all; they could have a key name instead if you've set one.
Related
I want to use AngularJS with Django however they both use {{ }} as their template tags. Is there an easy way to change one of the two to use some other custom templating tag?
For Angular 1.0 you should use the $interpolateProvider apis to configure the interpolation symbols: http://docs.angularjs.org/api/ng.$interpolateProvider.
Something like this should do the trick:
myModule.config(function($interpolateProvider) {
$interpolateProvider.startSymbol('{[{');
$interpolateProvider.endSymbol('}]}');
});
Keep in mind two things:
mixing server-side and client-side templates is rarely a good idea and should be used with caution. The main issues are: maintainability (hard to read) and security (double interpolation could expose a new security vector - e.g. while escaping of serverside and clientside templating by themselves might be secure, their combination might not be).
if you start using third-party directives (components) that use {{ }} in their templates then your configuration will break them. (fix pending)
While there is nothing we can do about the first issue, except for warning people, we do need to address the second issue.
you can maybe try verbatim Django template tag
and use it like this :
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
{% verbatim %}
<div ng-app="">
<p>10 is {{ 5 + 5 }}</p>
</div>
{% endverbatim %}
If you did separate sections of page properly then you can easily use angularjs tags in "raw" tag scope.
In jinja2
{% raw %}
// here you can write angularjs template tags.
{% endraw %}
In Django template (above 1.5)
{% verbatim %}
// here you can write angularjs template tags.
{% endverbatim %}
We created a very simple filter in Django 'ng' that makes it easy to mix the two:
foo.html:
...
<div>
{{ django_context_var }}
{{ 'angularScopeVar' | ng }}
{{ 'angularScopeFunction()' | ng }}
</div>
...
The ng filter looks like this:
from django import template
from django.utils import safestring
register = template.Library()
#register.filter(name='ng')
def Angularify(value):
return safestring.mark_safe('{{%s}}' % value)
So I got some great help in the Angular IRC channel today. It turns out you can change Angular's template tags very easily. The necessary snippets below should be included after your angular include (the given example appears on their mailing lists and would use (()) as the new template tags, substitute for your own):
angular.markup('(())', function(text, textNode, parentElement){
if (parentElement[0].nodeName.toLowerCase() == 'script') return;
text = text.replace(/\(\(/g,'{{').replace(/\)\)/g, '}}');
textNode.text(text);
return angular.markup('{{}}').call(this, text, textNode, parentElement);
});
angular.attrMarkup('(())', function(value, name, element){
value = value.replace(/\(\(/g,'{{').replace(/\)\)/, '}}');
element[0].setAttribute(name, value);
return angular.attrMarkup('{{}}').call(this, value, name, element);
});
Also, I was pointed to an upcoming enhancement that will expose startSymbol and endSymbol properties that can be set to whatever tags you desire.
I vote against using double parentheses (()) as template tag. It may work well as long as no function call is involved but when tried the following
ng:disabled=(($invalidWidgets.visible()))
with Firefox (10.0.2) on Mac I got a terribly long error instead of the intended logic. <[]> went well for me, at least up until now.
Edit 2012-03-29:
Please note that $invalidWidgets is deprecated. However I'd still use another wrapper than double braces. For any angular version higher than 0.10.7 (I guess) you could change the wrapper a lot easier in your app / module definition:
angular.module('YourAppName', [], function ($interpolateProvider) {
$interpolateProvider.startSymbol('<[');
$interpolateProvider.endSymbol(']>');
});
API docs.
You could always use ng-bind instead of {{ }}
http://docs.angularjs.org/api/ng/directive/ngBind
<span ng-bind="name"></span>
I found the code below helpful. I found the code here: http://djangosnippets.org/snippets/2787/
"""
filename: angularjs.py
Usage:
{% ng Some.angular.scope.content %}
e.g.
{% load angularjs %}
<div ng-init="yourName = 'foobar'">
<p>{% ng yourName %}</p>
</div>
"""
from django import template
register = template.Library()
class AngularJS(template.Node):
def __init__(self, bits):
self.ng = bits
def render(self, ctx):
return "{{%s}}" % " ".join(self.ng[1:])
def do_angular(parser, token):
bits = token.split_contents()
return AngularJS(bits)
register.tag('ng', do_angular)
If you use django 1.5 and newer use:
{% verbatim %}
{{if dying}}Still alive.{{/if}}
{% endverbatim %}
If you are stuck with django 1.2 on appengine extend the django syntax with the verbatim template command like this ...
from django import template
register = template.Library()
class VerbatimNode(template.Node):
def __init__(self, text):
self.text = text
def render(self, context):
return self.text
#register.tag
def verbatim(parser, token):
text = []
while 1:
token = parser.tokens.pop(0)
if token.contents == 'endverbatim':
break
if token.token_type == template.TOKEN_VAR:
text.append('{{')
elif token.token_type == template.TOKEN_BLOCK:
text.append('{%')
text.append(token.contents)
if token.token_type == template.TOKEN_VAR:
text.append('}}')
elif token.token_type == template.TOKEN_BLOCK:
text.append('%}')
return VerbatimNode(''.join(text))
In your file use:
from google.appengine.ext.webapp import template
template.register_template_library('utilities.verbatim_template_tag')
Source:
http://bamboobig.blogspot.co.at/2011/09/notebook-using-jquery-templates-in.html
You can tell Django to output {{ and }}, as well as other reserved template strings by using the {% templatetag %} tag.
For instance, using {% templatetag openvariable %} would output {{.
I would stick with a solution that uses both django tags {{}} as well angularjs {{}} with a either a verbatim section or templatetag.
That is simply because you can change the way angularjs works (as mentioned) via the $interpolateProvider.startSymbol $interpolateProvider.endSymbol but if you start to use other angularjs components like the ui-bootstrap you will find that some of the templates are ALREADY built with standard angularjs tags {{ }}.
For example look at https://github.com/angular-ui/bootstrap/blob/master/template/dialog/message.html.
If you do any server-side interpolation, the only correct way to do this is with <>
$interpolateProvider.startSymbol('<{').endSymbol('}>');
Anything else is an XSS vector.
This is because any Angular delimiters which are not escaped by Django can be entered by the user into the interpolated string; if someone sets their username as "{{evil_code}}", Angular will happily run it. If you use a character than Django escapes, however, this won't happen.
I am facing a very weird problem in one of my django projects. In my project I have a custom field class that handles foreign keys, one to one and many 2 many model fields. The class is some thing like the following.
from django import forms
class CustomRelatedField(forms.Field):
def __init__(self, model, limit=None, multiple=False, create_objects=True, *args, *kwargs):
self.model = model
self.limit = limit
self.multiple = multiple
self.create_objects = create_objects
super(CustomRelatedField, self).__init__(*args, **kwargs)
def clean(self, value):
""" Calls self.get_objects to get the actual model object instance(s)
from the given unicode value.
"""
# Do some value processing here
return self.get_objects(value)
def get_objects(self, values):
""" Returns the model object instances for the given unicode values.
"""
results = []
for value in values:
try:
obj = self.model.object.get_or_create(name=value)[0]
results.append(obj)
except Exception, err:
# Log the error here.
return results
def prepare_value(self, value):
""" Returns the value to be sent to the UI. The value
passed to this method is generally the object id or
a list of object id's (in case it is a many to many object).
So we need to make a database query to get the object and
then return the name attribute.
"""
if self.multiple:
result = [obj.name for obj in self.model.filter(pk__in=value)]
else:
result = self.model.object.get(pk=value)
return result
Recently while I was playing with the django-toolbar, I found out one of the pages that has a form with the above mentioned fields was ridiculously making multiple queries for the same objects again and again.
While debugging, I found out the prepare_value method was being called again and again. After some more debugging, I realized the culprit was the template. I have a generic template that I use for forms, It looks something like the following:
{% for field in form %}
{% if field.is_hidden %}
<!-- Do something here -->
{% endif %}
{% if field.field.required %}
<!-- Do something here -->
{% endif %}
<label>{{ field.label }}</label>
<div class="form-field">{{ field }}</div>
{% if field.field.widget.attrs.help_text %}
<!-- Do something here -->
{% elif field.errors %}
<!-- Do something here -->
{% endif %}
{% endfor %}
In the above code, each if statement calls the field class which calls the prepare_value method which then makes the database queries. Each of the following listed is making a database query, I am totally lost to why this is happening and have no clue about any solutions. Any help, suggestions would be really appreciated. Thanks.
field.is_hidden
field.field.required
field.label
field.label_tag
field
field.field.widget.attrs.help_text
field.errors
Also, why does this happen with my custom field class only, other fields (FKs, O2Os, M2M's) in the application and the application admin, just make one query, even though they are using a similar template.
Problem is with your prepare_value() method which does explicit queries. .get() does not get cached and always hits the db while iterating on .filter() queryset will evaluate that.
This might be causing you multiple queries.
This is not seen in default fields because they do not do any queries in prepare_value().
To resolve this, you can try to cache the value and result. If value hasn't changed, return cached result. Something like:
class CustomRelatedField(forms.Field):
def __init__(self, model, limit=None, multiple=False, create_objects=True, *args, *kwargs):
self.cached_result = None
self.cached_value = None
...
def prepare_value(self, value):
#check we have cached result
if value == self.cached_value:
return self.cached_result
if self.multiple:
result = [obj.name for obj in self.model.filter(pk__in=value)]
else:
result = self.model.object.get(pk=value)
#cache the result and value
self.cached_result = result
self.cached_value = value
return result
Not sure how good/bad this work around though!
I have a database of images. I want to display all the images in the database using a jinja2 template.
I send the database objects as follow:
class Default_tiles(db.Model):
name = db.StringProperty()
image = db.BlobProperty(default=None)
class MainPage(webapp2.RequestHandler):
def get(self):
# get all the default tiles in the database
default_tiles_query = Default_tiles.all()
defaultTiles = default_tiles_query.fetch(10)
template_values = {
'defaultTiles': defaultTiles # contain all the defaut tiles to be displayed
}
template = jinja_environment.get_template('index.html')
self.response.out.write(template.render(template_values))
The jinja2 template to display each image in each object in Default_tiles is:
<body>
{% for defaultTile in defaultTiles %}
{{ defaultTile.image }}
{% endfor %}
</body>
When this is run I get the following error log:
File "/Users/jamiefearon/Desktop/Development/My Programs/GAE Fully functional website with css, javascript and images/index.html", line 24, in top-level template code
{{ defaultTile.image }}
UnicodeDecodeError: 'ascii' codec can't decode byte 0x89 in position 0: ordinal not in range(128)
I suspect that I am doing something wrong with the line {{ defaultTile.image }}
Thanks all for helping.
You can't just throw binary data into html and display the image, you need to display the images using the IMG element.
You need to serve your images using a handler or display the images using inline base64 data.
i am kinda new to database design, but i would like to create three tables "User" and "Review" and "Topic" for a database in django.
I will try to explain it in detail here:
For example, I have User, Topic and Review models in models.py. one user can only write one review for one topic from other users.
let's say: Mike, John, Peter are the three Users.
Mike posted "Hello World" topic. John can only write one review for the topic "Hello World", Peter can also write one review for the same. John and Peter can not post another review for the same topic(they can only modify it). If Mike post another topic, John and Peter can post another review for the new topic. the same rule apply to other users.
please if you could, could you please provide some sample code for this issue? thanks a lot.
If you are trying to figure out how to set up your models.py, visit the django documentation, and look at Writing your first app (https://docs.djangoproject.com/en/dev/intro/tutorial01/). It goes from start to finish writing your first application and you will learn how the system works.
If you wanted more specifics for the paradigm of your case, here's what I would do. I would probably handle this in the view/template and submit/edit the review with Dajaxice calls to the database. If a review by the current user exists, it will show the data, if it doesn't it will be a blank entry that will use Dajax to submit the content. In the python method that the Dajax calls, you would try to find a review, and if one exists while attempting to add a new one, something went wrong and you can handle the error, otherwise it is saved for all to see.
For example, in models.py:
class User(models.Model):
name = models.CharField(max_length=128)
def __unicode__(self):
return self.name
class Review(models.Model):
title = models.CharField(max_length=64)
message = models.TextField()
topic = models.ForeignKey(Topic)
user = models.ForeignKey(User)
def __unicode__(self):
return self.title
class Topic
title = models.CharField(max_length=64)
message = models.TextField()
user = models.ForeignKey()
def __unicode__(self):
return self.title
in views.py:
class Post(models.Model): # This is defined a model, but not part of the data layer, it really is view code.
topic = None
your_review = None
other_reviews = None
def __unicode__(self):
return ''
def GetDetails(request):
posts = () # to be returned to and looped by the Template.
topics = Topic.objects.all().order_by('-posting_date') # posting_date descending.
for t in topics:
post = Post()
post.topic = t
post.your_review = Review.objects.filter(topic__id=t.id, user__id=<current_user_id>)
post.other_reviews = Review.objects.filter(topic__id=t.id, ~Q(user__id=<current_user_id>)
# Append to the posts array.
posts.append(post)
return render_to_response('index.htm', {'posts': posts}, context_instance=RequestContext(request))
in your index.htm:
{% if posts %}
{% for p in posts %}
<div>
<div class="title">{{ p.topic.title }}</div>
<div class="message">{{ p.topic.message }}</div>
<div class="other_reviews">
{% if p.other_reviews %}
{% for r in p.other_reviews %}
<div class="review_title">{{ r.title }}</div>
<div class="review_message">{{ r.message }}</div>
{% endfor %}
{% endif %}
<div>
<input type="text" value="{% if p.your_review %}{{ p.your_review.title }}{% endif %}">
</div>
<div>
<textarea>{% if p.your_review %}{{ p.your_review.message }}{% endif %}</textarea>
</div>
</div>
</div>
{% endfor %}
{% endif %}
I made a very minor mod to the GqlQuery to retrieve only specified records using the
'where' keyword. The output, however, displays all entries from the guestbook db!
(I need to filter the data by author)
Guestbook5_datastore code:
#greetings = db.GqlQuery("SELECT * FROM Greeting ORDER BY date DESC LIMIT 10")
greetings = db.GqlQuery("SELECT * FROM Greeting where greeting.author='mike'")
index.html code:
{% for greeting in greetings %}
{% if greeting.author %}
<b>{{ greeting.author.nickname }}</b> wrote:
{% else %}
An Anonymous person wrote:
{% endif %}
<blockquote>{{ greeting.content|escape }}</blockquote>
{% endfor %}
Your author property is not a string, so I don't think you can do
greeting.author='mike'
I'm surprised that you wouldn't get an error telling you that though, rather than it returning them all!
You're attempting to filter based on a property of another entity, which would require a join. This isn't supported in App Engine.