Google App Engine: Outputting 'values' from a SearchResult object on Jinja2 template. - google-app-engine

I would like to return the field values of a SearchDocument's object. For example, I have generated a SearchResult object using:
class SearchResult(Handler):
def get(self):
index = search.Index("INDEX_NAME")
results = index.search("Brian")
self.render('search-result.html', results = results)
The results object looks something like this:
search.SearchResults(results=[
search.ScoredDocument(
doc_id=u'6122080743456768',
fields=[search.TextField(name=u'full_name', value=u"Brian Jones"),
language=u'en',
rank=106509239L),
search.ScoredDocument(
doc_id=u'4714705859903488',
fields=[search.TextField(name=u'full_name', value=u"Brian Lara"),
language=u'en',
rank=106427057L)],
number_found=2L)
Inside search-result.html, how can I return the values of the fields?
...
<body>
{{ field_values }} #return the field values "Brian Lara" and "Brian Jones"
<body>
...

Start here:
{% for result in results %}
{{ result.fields[0].value }}
{% endfor %}
(You have a '[' mismatch in your fields. Fix that, then check the syntax)

Related

Initializing a modelchoicefield to a value in get_context_data()

I need to initialized a ModelChoiceField value to an instance retrieved in get_context_data() but it does not seem to work. I have tried .initial= but no luck so far.
This is the form
class PostEditForm(forms.ModelForm):
post_category = forms.ModelChoiceField(label='Category',queryset=Category.objects.all(),empty_label="--Select Category--",required=False)
class Meta:
model=Post
fields=('title','summary','content')
and this is the view
class EditPostView(LoginRequiredMixin, AjaxableResponseMixin, UpdateView):
model = Post
form_class = PostEditForm
template_name = 'postapp/editpost.html'
success_url = reverse_lazy('postapp:draftposts')
def get_context_data(self):
context = super().get_context_data()
post=self.get_object()
print(post)
try:
post_category = PostCategory.objects.get(post=post)
print(post_category)
except:
print("Post Category not yet assigned")
else:
context['form']['post_category'].initial = post_category
print(context['form']['post_category'])
return context
and here is the post category model
class PostCategory(models.Model):
post = models.ForeignKey(Post,on_delete=models.CASCADE)
category = models.ForeignKey(Category,on_delete=models.CASCADE)
def __str__(self):
return self.category.title
UPDATE
I forgot to mention I was rendering the form manually, here is the HTML
<select class="form-select" name={{form.post_category.html_name}} id='{{form.post_category.auto_id}}'
{% if form.post_category.field.required %}required{% endif %}>
{% for value, text in form.post_category.field.choices %}
<option
{% if form.post_category.value == value|stringformat:"s" %}selected="selected"{% endif %} value={{value}}>{{text}}
</option>
{% endfor %}
</select>
The value in the initial needs to be PK.
So:
context['form']['post_category'].initial = post_category.id
Also, since post and post category are mapped 1-to-many, PostCategory.objects.get() can return multiple post categories which raises MultipleObjectsReturned error. I suggest using a combination of filter and first so you get the first category if there are many. You will probably change this logic to something that makes sense but it's important to be aware of it.
post_category = PostCategory.objects.filter(post=post).first()
Bonus points: override the get_initial method as it's better practice when using class based views.
def get_initial(self):
initial = super().get_initial()
post=self.object
print(post)
post_category = PostCategory.objects.filter(post=post).first()
if post_category is not None:
print(post_category)
initial.update({'post_category': post_category.id})
print(initial['post_category'])
else:
print("Post Category not yet assigned")
return initial

Twig: Append to array inside array/object

I have an object which, in JSON, would look like this:
{
'class': ['nav-link', 'dropdown-toggle'],
'data-toggle': ['dropdown']
}
I need to then be able to append another class to the class array inside the object.
This code doesn't seem to work; it just overwrites the class array.
{% set link_attribs = { 'class' : ['nav-link', 'dropdown-toggle'], 'data-toggle':'dropdown'} %}
{% set link_attribs = link_attribs|merge({'class': ['highlighted']}) %}
Really I want to do something like this, but it just throws a punctuation error.
{% set link_attribs.class = link_attribs.class|merge(['highlighted']) %}
Any ideas?
Using Twig, you can't set object properties directly, so "set (...).class" will never work. But instead, you can create a new variable that will inherit from both default and options values (just like in most JavaScript codes).
For example:
{%
set options = link_attribs | merge({
'class': link_attribs.class | merge(['highlighted'])
})
%}
{% for class in options.class %}
{{ class }}
{% endfor %}
Will display:
nav-link
dropdown-toggle
highlighted
See fiddle.
This looks like it works:
{% set c = link_attribs.class %}
{% set c = c|merge(['highlighted']) %}
{% set link_attribs = link_attribs|merge({'class': c}) %}
Not sure if its the most elegant way though.

How to display multiple data sets in Symfony2

I am totally new to Symfony and i d like to know how I manage to display multiple data sets from my db in a twig...
untill now my attempt is the following:
class ProjController extends Controller
{
/**
* #Route("/", name="_projekte")
* #Template("FHBingenBundle:projekte:list.html.twig")
*
*/
public function indexAction()
{
$projekte = $this->getDoctrine()
->getRepository('FHBingenBundle:Projekt')->findAll();
return $projekte;
}
}
to get all the data sets. Here is where my Problem starts... how do I extract the data from the array? (the entity has multiple columns but i only want two of them, name and description)
{% extends "FHBingenBundle::layout.html.twig" %}
{% block content %}
<table>
<?php foreach ($liste as $projekt ?>
<tr><p>{{ $projekt->getName() }}</p></tr>
<?php endforeach;?>
</table>
{% endblock %}
thats how I tried to do it but apperently I am not allowed to use $ inside of {{}}? atleast thats what the error says
You should consider reading the cookbook.
Since you are using twig, think about using twig templating system.
{% for item in navigation %} // equivalent to foreach($navigation as $item) {
{{ item.name }} // equivalent to $item->name or $item->getName() or $item->hasName()
{% endfor %} // equivalent to }
EDIT : I don't really remember but it seems that you have to return an array for the twig templating system. return array('projects' => $projects);

Can't iterate over GqlQuery object

I have a Blog model which contains 4 entities, subject, blog, time_created and day_created. I query all the values and assign it to an object which pass to a jinja2 template. In the template I iterate over the object and print each different entity which results in the display of each blog post.
The model for the data is:
class Blog(db.Model):
subject = db.StringProperty(required = True, multiline = True)
blog = db.TextProperty(required = True)
time_created = db.DateTimeProperty(auto_now_add = True)
day_created = db.DateProperty(auto_now_add = True)
And I query all the entries to display as individual posts as such:
posts = db.GqlQuery('SELECT * FROM Blog ORDER BY time_created DESC')
and I pass these out to the template
class Mainpage(BaseHandler):
def get(self):
posts = Blog_posts()
logging.info(posts)
if posts:
end_time = time.time() - start_time
logging.info(end_time)
logging.info(start_time)
userLogin = self.checkLogin()
cookieVal = self.read_secure_cookie('user-id')
if cookieVal:
u_id = cookieVal.split('|')[0]
usr_instance = Users.get_by_id(int(u_id))
if usr_instance:
name = usr_instance.username
if userLogin == True and name:
self.render("blog.html", posts = posts, userLogin = userLogin, user_name = name, end_time = int(end_time))
logging.info("Logged in = " + str(userLogin))
else:
self.render("blog.html", posts = posts, userLogin = userLogin, user_name = "", end_time = int(end_time))
else:
self.render("blog.html", posts = posts, userLogin = userLogin, user_name = "", end_time = int(end_time))
the function render() is :
def render(self, template, **kw):
self.response.out.write(render_str(template, **kw))
I have a main template blogbase.html which I inherit to all other pages and it contains these lines which I use for template inheritance :
<div class="content">
{% block content %}
{% endblock %}
</div>
and in the html file that displays the main blog page and inherits this is :
{% extends "blogbase.html" %}
{% block content %}
{% for post in posts %}
<div class="one_post">
<div class="subject_title">
<div class="day">{{post.day_created.strftime("%d %b %Y")}}</div>
<a href="/blog/{{post.key().id()}}" target="_blank">
{{post.subject}}
</a>
</div>
<div class="post">
{{post.blog}}
</div>
</div>
{% endfor %}
<div class="query">
Queried {{end_time}} seconds ago
</div>
{% endblock %}
I added a debugging line to see whether the query works and it returns the true with the following :
<google.appengine.ext.db.GqlQuery object at 0x7f99f03cd050>
But I am not able to iterate over this object as in the templates, regular html works, but the part between the for loop doesn't render.
Is there something wrong in my query ? Or am I using the templating engine wrong ?
2 things I've noticed.
You are using a query in your templates to iterate over it and do what? Print info? You need to get the entities. Either get them when you query or iterate and fetch.
posts = db.GqlQuery('SELECT * FROM Blog ORDER BY time_created DESC').fetch(1000)
Also if you are passing dicts to jinja you might wanny check that you are using {% for post in posts.iteritems() %} but this is not the case here.

Django - How to query and display multiple relationship struture

I'm building a RSS feed reader where users can add own feeds and categories. I want to store content all of the the feeds in db and run a script that would fetch that content for all of the feed_url present in db periodically (I had working project where each feed is fetched live and it wasn't good idea)
Now after several attempts I got into the following model structure.
class Category(models.Model):
name = models.CharField(unique=False, max_length=64)
user = models.ForeignKey(User)
def __unicode__(self):
return self.name
class Meta:
ordering = ('name',)
class Feed(models.Model):
feed_url = models.URLField(unique=True)
def __unicode__(self):
return self.feed_url
class UserFeed(models.Model):
feed = models.ForeignKey(Feed)
title = models.CharField(max_length=256)
category = models.ForeignKey(Category)
user = models.ForeignKey(User)
def __unicode__(self):
return self.title
class Post(models.Model):
feed = models.ForeignKey(Feed, related_name='feed_posts')
## starting from here, my cronjob / script populates the data (using feedparser lib)
title = models.CharField(max_length=256)
content = models.TextField()
link = models.URLField(max_length=512)
dt_published = models.DateTimeField()
dt_cached = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return '%s (%s)' % (self.feed, self.title)
class Meta:
ordering = ('-dt_published',)
What I'm looking for now is ability for pull into a view and later into templates, the following entities:
->Category -> Feed -> Posts
In my previous version where Feed and UserFeed fields were stored in one table/model, I had such view:
def category(request, category_id):
user = request.user
page_title = "Category: "
category = get_object_or_404(Category.objects.filter(id=category_id, user=user)).feed_set.all()
category_name = Category.objects.get(id=category_id)
context = {
'page_title': page_title,
'category': category,
'category_name': category_name,
}
return expand_context_and_render(request, context, 'reader/category.html')
and this is my template:
{% for feed in category %}
<p>{{ feed.title }}</p>
{% for post in feed.post_set.all|slice:"6" %}
<p>{{ post.title }}</p>
<p>{{ post.content }}</p>
<p>{{ post.dt_published|timesince }} ago.</p>
{% endfor %}
{% endfor %}
And it was working as intended.
Now, since I don't want to have multiple copies of feed_url in my database, I think the new models are OK, but I simply can't figure out how to query and display this new structure which has upstream and downstream relationships. I was looking at select_related but didn't get it to work. Could you please help ?
I eventually found the solution myself. It's bit hacky :( but does the job.
def category(request, user_category_id):
user = request.user
page_title = "Category: "
user_category = get_object_or_404(Category.objects.filter(id=user_category_id, user=user))
user_feeds = UserFeed.objects.filter(category=user_category, user=user)
context = {
'page_title': page_title,
'user_category': user_category,
'user_feeds': user_feeds,
}
return expand_context_and_render(request, context, 'reader/category.html')
and template:
{% for user_feed in user_feeds %}
<p><strong>{{ user_feed }}</strong></p>
{% for post in user_feed.feed.post_set.all|slice:"6" %}
<div class="col-md-4">
<p>{{ post.title|truncatechars:"45" }}</p>
<p>{{ post.content|striptags|safe|truncatechars:"85" }}</p>
<p class="feed_date">{{ post.dt_published|timesince }} ago.</p>
<hr />
</div>
{% endfor %}
{% endfor %}

Resources