How to retrieve the children in Django - django

I have a model Category like so :
class Category(TimeStampedModel):
category_parent = models.ForeignKey('self', blank=True, null=True)
name = models.CharField(max_length = 200)
slug = models.SlugField(unique=True)
def __str__(self):
return self.name
What I want is to display all the categories that do not have parents at first, and then, in nested lists, their respective children : for example :
Flowers
Lilac
Rose
Trees
Maple
So what I have tried is that :
def get_categories(request):
categories = Category.objects.filter(category_parent=None)
return {'categories' : categories}
But when I try to display the children of each category, none appears, following my example, I only get Flowers and Trees..
<ul class="nav-list">
{% for category in categories %}
<li class="nav-item"><a class="nav-link" href="#">{{ category.name }}</a>
{% if category.categories %}
<ul class="nav-submenu">
{% for subcategory in category.categories %}
<li class="nav-submenu-item">{{ subcategory.name }}</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
How can I get the children too ?

You didn't specify related name "categories" to the category_parent field so you can't access it via category.categories. You can try using this expression
{% for subcategory in category.category_set.all %}
<!-- subcategory staff -->
{% endfor %}
in your template.

Related

How to regroup blog posts with multiple categories by category in Django template

I have Blog with posts that have multiple categories
class BlogDetailPage(Page):
heading = models.CharField(max_length=150, blank=False, null=False)
categories = ParentalManyToManyField("blog.BlogCategory", blank=False)
...
class BlogCategory(models.Model):
title = models.CharField(max_length=30,unique=True)
slug = AutoSlugField(populate_from='title')
...
My posts are as follows:
Post 1: Category A
Post 2: Category A, Category B
Post 3: Category B
I want regroup posts by category as below:
Category A
Post 1
Post 2
Category B
Post 2
Post 3
My current solution is not giving me correct results.
{% regroup posts by categories.all as posts_by_categories %}
<ul>
{% for category in posts_by_categories %}
<li>{{ category.grouper.0 }} # first category name
<ul>
{% for post in category.list %}
<li>{{ post.id }}, {{post.categories.all}}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
Amy ideas?
If you don't have to use 'regroup', How about using 'related_name'?
In python
class BlogDetailPage(Page):
categories = ParentalManyToManyField("blog.BlogCategory", blank=False, related_name="blog_posts")
...
In Django_html
<ul>
{% for category in categories.all %}
<li>{{ category.title }} # first category name
<ul>
{% for post in category.blog_posts.all %}
<li>{{ post.id }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>

Django view function for navbar included

I have my page only for navigation bar and I include it in base page. Now I have a menu in that navigation bar and links I get from database(that links are my categories).
But how can I call my function in views without path, because I don't need to have path for navigation bar? And I need that view function to get data from database.
models.py
class Item(models.Model):
title = models.CharField(max_length=100)
price = models.FloatField()
discount_price = models.FloatField(blank=True, null=True)
category = models.CharField(choices=CATEGORY_CHOICES, max_length=2)
label = models.CharField(choices=LABEL_CHOICES, max_length=1)
slug = models.SlugField()
description = models.TextField()
info = models.TextField(default="Informacion a Completar")
image = models.ImageField(blank=True)
views.py
def CategoryView(request):
context = {
'items' : Item.objects.all()
}
return render(request, 'categories_bar.html', context=context)
categories_bar.html
<li class="nav-item"></li>
{% for category in items %}
<div> {{ category.category }} </div>
{% endfor %}
</li>
base.html
{% include "categories_bar.html" %}
You can use block tags like this:
base.html:
<nav>
<ul>
{% block categories %}{% endblock %}
</ul>
</nav>
<!-- replace navbar code with yours -->
categories_bar.html:
{% block categories %}
{% for category in items %}
<li class="nav-item"></li>
<div> {{ category.category }} </div>
</li>
{% endfor %}
{% endblock %}

How to display a list of posts in a list of categories in Django

I am looking for my web page to display a list of categories and a list of each post within the category.
For example:
However, it is looping through and displaying each category and associated post separately, like this:
Here is Template:
<ul>
{% for p in object_list %}
<li>
{{p.category.name}}
<ul>
<li>
{{p.title}}
</li>
</ul>
</li>
{% endfor %}
</ul>
Model
class Category(models.Model):
name = models.CharField(max_length=200, blank=True, null=True)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=100)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='category', null=False)
Views
class CategoryList(ListView):
template_name = 'category_list.html'
def get_queryset(self):
return Post.objects.all().select_related('category')
Try changing your template code to this
{% regroup object_list by category as post_list %}
<ul>
{% for post_category in post_list %}
<li>{{ post_category.grouper }}
<ul>
{% for post in post_category.list %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
try this:
views.py:
def get_queryset(request):
categorys = {category: Post.objects.filter(category = category) for category in Category.objects.all()}
Template:
<ul>
{% for category, posts in categorys.items %}
<li>
{{category.name}}
{% for comment in comments %}
<ul>
<li>
{{posts.title}}
</li>
</ul>
{% endfor %}
<li>
{% endfor %}
</ul>
Use 2-layer nested loops to display posts and categories, each item in the outer loop is a category, and each item category in the inner loop is the title of the posts.
You can do that in the template with regroup. Also order the items to be grouped by the field you wish to group with.
https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#regroup

MPTT multiple parents breadcrumbs

Let's say I have a simple model set:
class Category(MPTTModel):
name = CharField(max_length=50)
parent = TreeForeignKey(
'self',
null=True,
blank=True,
related_name='children',
db_index=True
)
class Record(Model):
name = CharField(max_length=50)
category = TreeManyToManyField(SectionArt)
And let's imagine I have a Record that belongs to 3 different categories. How do I make breadcrumbs track from which category I opened my record?
You can track where user came from with request.META['HTTP_REFERER']
views.py
def get_context_data(self, **kwargs):
c = super(RecordDetail, self).get_context_data(**kwargs)
if 'HTTP_REFERER' in self.request.META:
referer = self.request.META['HTTP_REFERER'].split('/')[-2]
c['categories'] = [models.Category.objects.get(slug=referer)]
else:
c['categories'] = self.object.categories.all()
return c
template.html
<ul class="breadcrumbs">
<li>{{ sections.home.title }}</li>
{% if categories %}
{% with category=categories.0 %}
{% for obj in category.get_ancestors %}
<li>{{ obj.title }}</li>
{% endfor %}
<li>{{ category.title }}</li>
{% endwith %}
{% endif %}
<li class="current">{{ object.short_title }}</li>
</ul>
Source

Total Count In Django

I have models, views & template in Django and want to display the total count of category.
class Entry (models.Model):
title = models.CharField(max_length=200)
category = models.ForeignKey('entry.Category')
class Category(models.Model):
title = models.CharField(max_length=100)
parent = models.ForeignKey('self', blank=True, null=True, related_name='children')
def category(request):
category = Category.objects.all()
return render_to_response('category.html', locals(), context_instance=RequestContext(request))
<ul>
{% for category in category %}
<li>{{ category.title }} ({{ category.entry_set.all.count }})</li>
{% endfor %}
</ul>
Current output:
-Category 1 (0)
--Sub Category 1 (3)
--Sub Category 2 (6)
And desire output is like this:
-Category 1 (9)
--Sub Category 1 (3)
--Sub Category 2 (6)
How to get that output?
Use category.entry_set.count instead of category.entry_set.all.count.
Also, you are using same variable name category for referencing multiple values, you may want to change that.
Update template as:
<ul>
{% for cat in category %}
<li>{{ cat.title }} ({{ cat.entry_set.count }})</li>
{% endfor %}
</ul>
Solved by using Django-MPTT and update my view & template like this:
views.py:
def category(request):
category = Category.tree.add_related_count(Category.objects.all(), Entry, 'category', 'cat_count', cumulative=True)
return render_to_response('category.html', locals(), context_instance=RequestContext(request))
category.html:
{% recursetree category %}
<ul>
{{ node.title }} ({{ node.cat_count }})
{% if not node.is_leaf_node %}
<li class="children">
{{ children }}
</li>
{% endif %}
</ul>
{% endrecursetree %}