How can you loop through all of the children of a model? - django-models

In Django I am trying to loop through all of the children of my Todo model. But whenever I try to run it, it gives me an AttributeError that says "Manager isn't accessible via Todo instances". My code looks like this:
{% extends 'base.html' %}
{% block content %}
<h3>Tasks</h3>
{% for t in model.objects.all %} <!-- Error -->
<p>{{t.name}}</p>
{% endfor %}
{% endblock %}
{% block options %}
<li class="bg-light py-3 w-100 px-4 rounded text-nowrap fs-4">
<button class="text-decoration-none text-dark">Save</button>
</li>
{% endblock %}
I tried to just put the model in the context, and then I got an error in the HTML, so I figured out that it happened when I tried to reference 'model.objects.all'.

Inside of your view you need to specify what django should pass to the template. It does not serve the entire Database; therefore queries like in model.objects.all inside of your templates are not allowed.
Specify the queryset inside your views.py:
def todo_view(request):
context = {}
context['my_todos'] = my_todo_model.objects.all()
context['most_important_todo'] = my_todo_model.objects.get(pk=1)
# put your own logic inside the `.get` method above
return render(request, 'my_template.html' context)
And then access it inside of your template like so:
{% for t in my_todos %}
<p>{{ t.name }}</p>
{% endfor %}
{{ most_important_todo.name }}
Because we put a queryset inside of my_todos we can loop over it in the template. most_important_todo ist just a single object passed to the template, so we can access its properties (e.g. the name) directly.
Let me know how it goes

Related

syntax in wagtail HTML template file

In below HTML template of Wagtail,
<h1>{{ page.title }}</h1>
<div>{{ page.intro }}</div>
{% for post in page.get_children %}
<h2>{{ post.title }}</h2>
<p>{{ post.first_published_at }}</p>
<p>{{ post.owner }}</p>
{% if post.specific.rncategory.all.count %}
{% for ctgy in post.specific.rncategory.all %}
{{ctgy.category.name}}
{% endfor %}
{% endif %}
{% for tg in post.specific.rntags.all %}
<button type="button">{{tg.tag.name}}</button>
{% endfor %}
{% endfor %}
Q1: Why we use page.get_children & post.specific.rncategory.all.count instead of page.get_children() and post.specific.rncategory.all().count() which are expected to be corrected ?
And It is the other way around (page.get_children is invalid) in the PDB debug interaction session.
(Pdb++) obj.get_children()[0]
<Page: Detail>
(Pdb++) obj.get_children()[0].specific.rncategory.all.count
*** AttributeError: 'function' object has no attribute 'count'
(Pdb++) obj.get_children()[0].specific.rncategory.all
<bound method BaseManager.all of <modelcluster.fields.create_deferring_foreign_related_manager.<locals>.DeferringRelatedManager object at 0x7f7076003790>>
(Pdb++) obj.get_children()[0].specific.rncategory.all()
<QuerySet []>
(Pdb++) obj.get_children()[1].specific.rncategory.all()
<QuerySet [<Link_PostDetail_Category: Link_PostDetail_Category object (2)>]>
(Pdb++) obj.get_children()[1].specific.rncategory.all().count()
1
(Pdb++) obj.get_children()[0].specific.rncategory.all().count()
0
(Pdb++)
This is the normal behaviour of the Django template language - by design, Django template code is not equivalent to Python.
Django template syntax never uses () for function calls. Instead, whenever a variable lookup results in a callable, it will automatically be called with no arguments. See "Behind the scenes" under https://docs.djangoproject.com/en/stable/ref/templates/language/#variables.

HubL / Twig: Not finding value from array

In HubSpot, I've created a custom module called footer. footer has five field types of menu:
I've created an array where all five of the above menu ID's are pushed to an array. I've done this via a template partial file which is included in my footer module.
<!-- creating array -->
{% set footer_id_array = [] %}
<!-- push menu id's to array -->
{% do footer_id_array.append(module.menus.menu_column_1) %}
{% do footer_id_array.append(module.menus.menu_column_2) %}
{% do footer_id_array.append(module.menus.menu_column_3) %}
{% do footer_id_array.append(module.menus.menu_column_4) %}
{% do footer_id_array.append(module.menus.menu_column_5) %}
Running {{ footer_id_array }} shows all the IDs in the array, i.e.
[29420054435, 29420223163, 29420054590, 29420158158, 29420071857]
So this is correct, the array contains the IDs.
Now, for each item in this array, I want to generate a nav, so in my footer custom module, I have the following:
{% set iterations = range(0, 5) %}
{% for i in iterations %}
<nav>
{% menu id="{{ footer_id_array[i] }}" %}
</nav>
{% endfor %}
However, on my page, this just prints HubSpots default menus, not the ones assigned to the ID's.
Why is this?

Wagtail Show latest blog posts on Homepage through a streamfield

I have 3 mains sections in my site, homepage, blog index, and blog specific. I am using the streamfield function in wagtail to order various sections in the homepage. One of those sections is for the latest three blog posts.
I have done this for the blog index page, but can't grab the latest blog posts in the streamfield.
My model looks like this
class CaseStudiesIndex(Page):
def casestudies(pages):
casestudies = CaseStudyPage.objects.all().order_by('-first_published_at')
return casestudies
intro = RichTextField(blank=True)
content_panels = Page.content_panels + [
FieldPanel('intro', classname="full")
]
class LatestPosts(blocks.StructBlock):
static = blocks.StaticBlock(admin_text='Latest posts: no configuration needed.',)
def casestudies(pages):
casestudies = CaseStudyPage.objects.all().order_by('-first_published_at')[:3]
return casestudies
class Meta:
icon = 'doc-full'
label = 'Latest Posts'
template = 'blocks/_latestPosts.html'
class HomePage(Page):
blocksbody = StreamField([
('lead_banner', LeadBanner()),
('latest_posts', LatestPosts()),
('team', Team())
],null=True,blank=True)
content_panels = Page.content_panels + [
StreamFieldPanel('blocksbody'),
]
In my block folder I am calling the file fine and it renders the wrapper fine but I can't grab any of the data, I have tried a bunch of ways but nothing returns.
{% load wagtailcore_tags wagtailimages_tags %}
{% load static %}
<section>
<div class="wrapper__inner">
<ul>
{% for case in self.casestudies %}
{{case.title}}
{% endfor %}
{% for case in self.case_studies %}
{{case.title}}
{% endfor %}
{% for case in self.latest_posts %}
{{case.title}}
{% endfor %}
{% for case in page.casestudies %}
{{case.title}}
{% endfor %}
{% for case in page.case_studies %}
{{case.title}}
{% endfor %}
{% for case in page.latest_posts %}
{{case.title}}
{% endfor %}
</ul>
</div>
</section>
For the Blog Index page that does work I do the following.
{% extends "inner_base.html" %}
{% load wagtailcore_tags %}
{% block body_class %}template-case-studies{% endblock %}
{% block content %}
<section>
<div class="wrapper__inner">
<h1>{{self.title}}</h1>
<ul>
{% include "blocks/CaseStudiesLatestBlock.html" %}
</ul>
</div>
</section>
{% endblock %}
And the CaseStudiesLatestBlock.html which works fine looks like
{% load wagtailcore_tags wagtailimages_tags %}
{% load static %}
{% for case in self.casestudies %}
<li>
<strong>{{ case.title }}</strong>
</li>
{% endfor %}
Defining your own methods on a StructBlock won't work - the self (or value) variable you receive on the template is just a plain dict, not the StructBlock object itself. (This might seem counter-intuitive, but it's consistent with how blocks work in general: just as a CharBlock gives you a string value to work with and not a CharBlock instance, StructBlock gives you a dict rather than a StructBlock instance.)
Instead, you can define a get_context method (as documented here) to provide additional variables to the template:
class LatestPosts(blocks.StructBlock):
static = blocks.StaticBlock(admin_text='Latest posts: no configuration needed.',)
def get_context(self, value, parent_context=None):
context = super(LatestPosts, self).get_context(value, parent_context=parent_context)
context['casestudies'] = CaseStudyPage.objects.all().order_by('-first_published_at')[:3]
return context
You can then access the casestudies variable in the template, e.g. {% for case in casestudies %}.

django template tags, work with an array output

I created a tag which output is an array:
from django import template
register = template.Library()
def create_array(context):
output=[1,2,3,4]
return output
register.simple_tag(takes_context=True)(create_array)
When I call this tag in the template: {% load create_array %} {% create_array %}, the array is printed, but I can't access to each element in this way:
{% load create_array %}
{% for i in create_array %} {{i}} {% forend %}
Any idea how can I access to each element?
The error is during template rendering: Exception Value: 'create_array' object is not iterable.
PS: I need "context" in the tag, so I just wrote a short example. I'm using Django version 1.6.2
#laffuste has a good point that you need to use the as command to store the array into a template variable before you iterate through it. However, there's a slightly neater way to write the tag -- this is, in fact, precisely what Assignment Tags were made for:
from django import template
register = template.Library()
#register.assignment_tag(takes_context=True)
def create_array(context):
return [1,2,3,4]
That's it -- the assignment tag does the nasty work of parsing and return a template-variable-friendly output. Everything in laffuste's answer for the template is exactly what you'd need, but just so you can have it all in one place, here it is reproduced again so it's all in one place:
{{ load my_custom_tags }}
{% create_array as my_array %}
{% for item in my_array %}
{{ item }}
{% endfor %}
To get an index of each object in the forloop, use a forloop.counter like so:
{% load create_array %}
{% for i in create_array %}
{{ forloop.counter }}
{% forend %}
If you want to do something when you hit a certain count in the forloop, then use the following code:
{% for i in create_array %}
{% if forloop.counter == 1 %}
Do something with {{ i }}.
{% endif %}
{% endfor %}
Here is the Django Documentation for the forloop counter:
https://docs.djangoproject.com/en/dev/ref/templates/builtins/#for
I'm afraid there's no simpler way than...
from django import template
from django.template.base import TemplateSyntaxError
register = template.Library()
#register.tag(name='create_array')
def create_array(parser, token):
class ArrayCreator(template.Node):
def __init__(self, var_name):
self.var_name = var_name # output variable
def render(self, context):
context[self.var_name] = [1, 2, 3, 4] # access to context
return ''
args = token.contents.split() # "create_array", "as", VAR_NAME
if len(args) != 3 or args[1] != 'as':
raise TemplateSyntaxError("'create_array' requires 'as variable' (got %r)" % args)
return ArrayCreator(args[2])
Usage in Template:
{{ load my_custom_tags }}
{% create_array as my_array %}
{% for item in my_array %}
{{ item }}
{% endfor %}
But maybe someone will come with something lighter and nicer?

Jinja2 in google appengine extended template repeates base templete

Ok I have a base.html and I try to use that for my header menu and footer. In my other template I loop over items and display them on the page. My problem is the the other template is repeating my base.html like it's in the loop. I hope someone can show me the error in My ways.
Here is my base.html code:
<div class="menu">
<ul class="nav">
<li>Home</li>
<li>New Entry</li>
<li>Sign-up</li>
{% if user %}
<li>{{user.name}}</li>
<li>Log-Out</li>
{% else %}
<li>Log-In</li>
{% endif %}
</ul>
​
This is in the base.html also but didn't paste correctly.
<div id="content">
{% block content %}
{% endblock %}
</div>
And here is the sub template code:
{% extends "base.html" %}
{% block content %}
{% for p in posts %}
{{ p.render() | safe }}
<br><br>
{% endfor %}
<div>
{{text}}
</div>
{% endblock %}
Please help
Edit:
edit2: removed link and found my problem I was calling the wrong html file in render()
Be kind Newbie here
Looks ok. Are you sure you don't have a loop in the python code that renders the template?

Resources