Using MPTT do get_children in templates (at runtime) - django

my template receives a variable called categories, and I want to list the categories that are "sons" of its father categories
this is my code in template
{% for category,structure in categories|tree_info %}
{% if structure.new_level %}
<li>{{ category.name }} </li>
{% endif %}
{% for level in structure.closed_levels %}
<li>{{level.name}}
{% endfor %}
<ul class="noJS">
{% for cat in category.get_children|tree_info %}
<li>{{ cat.name }}aa </li>
{% endfor %}
</ul>
{% endfor %}
this is the model
class Category(MPTTModel):
name = models.CharField(max_length=50, unique=True)
description = models.TextField(blank=True)
parent = TreeForeignKey('self', null=True, blank=True, related_name='children')
class MPTTMeta:
order_insertion_by = ['name']
def __unicode__(self):
return self.name
any idea?

This worked
{% for category in categories %}
<li>
{{ category.name }}
<ul class="noJS">
{% for cat in category.get_children %}
<li>{{ cat.name }} </li>
{% endfor %}
</ul>
</li>
{% endfor %}

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>

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

access foreign key via a manytomany relationship in django

I have a foreign key that is in turn a many to many relation like the following:
Persons<-M2M->Role(ManyToOne)->Name
The model:
class Person(models.Model):
mail=models.EmailField()
firstName=models.CharField(max_length=200)
lastName=models.CharField(max_length=200)
phoneNumber=PhoneNumberField()
streetAdress=models.CharField(max_length=200)
zipcode=models.CharField(max_length=200)
city=models.CharField(max_length=200,default="Göteborg")
country=models.CharField(max_length=200,default="Sweden")
def __str__(self):
return "%s %s" % (self.firstName,self.lastName)
class Meta:
ordering = ('firstName','lastName')
class Role(models.Model):
role=models.CharField(max_length=200)
person=models.ManyToManyField(Person)
def __str__(self):
return self.role
class Meta:
ordering = ('role',)
class Name(models.Model):
name=models.CharField(max_length=200)
role=models.ForeignKey(Role,on_delete=models.CASCADE)
def __str__(self):
return self.name
class Meta:
ordering = ('name',)
class Address(models.Model):
I can acces the manyTomany field from persons and roles but I cannot access names.
the template:
{% extends "artdb/base.html" %}
{% block content1 %}
<ul>
{% for p in ans %}
<h5>First name: {{p.firstName}}</h5>
<h5>Last name: {{p.lastName}}</h5>
<h5>Phone: {{p.phoneNumber}}</h5>
<h5>Adress: {{p.streetAdress}}</h5>
<h5>Zip Code: {{p.zipcode}}</h5>
<h5>City: {{p.city}}</h5>
<hr>
{% endfor %}
</ul>
{% endblock content1 %}
{% block content2 %}
<ul>
{% for p in ans %}
{% for r in p.role_set.all %}
<h5>{{ r.role }}</h5>
{% endfor %}
{% endfor %}
<hr>
</ul>
{% endblock content2 %}
{% block content3 %}
<ul>
{% for p in ans %}
{% for r in p.role_set.all %}
<h5>{{ r.name }}</h5>
{% endfor %}
{% endfor %}
<hr>
</ul>
{% endblock content3 %
I konow that I have to iterate to get manyTomany, but is it the same with oneTomany?
how do I access Names from Persons via Role?
}
here is the solution for those interested. (thanks daniel roseman). Iterate through every relation. Here the first relation is many to many and the second many to one:
{% block content3 %}
<ul>
{% for p in ans %}
{% for r in p.role_set.all %}
{% for n in r.name_set.all %}
<h5>{{ n }}</h5>
{% endfor %}
{% endfor %}
{% endfor %}
<hr>
</ul>
{% endblock content3 %}

combining two or more querysets from different models in django

Main model:
class MainCategory(models.Model):
title = models.CharField(max_length=120, unique=True)
App#1:
class Category(models.Model):
title = models.CharField(max_length=120, unique=True)
main_category = models.ForeignKey(MainCategory, default=1, related_name='car_category')
App#2:
class Category(models.Model):
title = models.CharField(max_length=120, unique=True)
main_category = models.ForeignKey(MainCategory, default=1, related_name='classifieds_category')
on home page I want a combined list of both category list items as follows.
{% for object in main_cat_list %}
{{ object.title }}
{% for item in object.car_category %}
{{ item.title }}
{% endfor %}
{% endfor %}
How I can insert classifieds category also inside this list?
If you merely want to also display the classified_category as you have the car_category.
{% for object in main_cat_list %}
{{ object.title }}
{% for item in object.car_category %}
{{ item.title }}
{% endfor %}
{% for item in object.classified_category %}
{{ item.title }}
{% endfor %}
{% endfor %}

Displaying Nested ManyToMany Relation

I'm having nested many to many relation in my models.py and I've got the display partially working. I have 2 questions:
Is there a way to simplify the presentation, e.g. by inlineformset?
How to I access nested context variables in the template form (see line {% for objective in selected_objectives %} )?
Please let me know if there is a way to make my question more clear
models.py
class Process(models.Model):
title = models.CharField(max_length=200)
desc = models.TextField('process description', blank=True)
def __str__(self):
return self.title
class Objective(models.Model):
process = models.ManyToManyField(Process, verbose_name="related processes", blank=False)
title = models.CharField(max_length=200)
desc = models.TextField('objective description', blank=True)
def __str__(self):
return self.title
class Risk(models.Model):
objective = models.ManyToManyField(Objective, verbose_name="related objectives", blank=False)
title = models.CharField(max_length=200)
desc = models.TextField('risk description', blank=True)
def __str__(self):
return self.title
views.py
#login_required
def detailed_list(request):
#context = RequestContext(request)
obj = []
ri = []
all_processes = Process.objects.order_by('id') #[:1]
for p_index,p in enumerate(all_processes):
obj.append(p.objective_set.all()) #appending objectives for each process
for o_index,o in enumerate(obj[p_index]):
ri.append(o.risk_set.all().values()) #appending risks for each objective
context = {'all_processes': all_processes,
'selected_objectives': obj,
'selected_risks': ri
}
return render(request, 'repository/detailed.html', context)
template detailed.html
<p>Create new Process
</p>
{% if all_processes %}
No: {{ all_processes|length }}
<ul>
{% for process in all_processes %}
<li>{{ process.title }} {{ forloop.counter0 }}</li>
<ul>
{% if selected_objectives %}
{% for objective in selected_objectives %}
<!-- see here --> <li>{{ objective.title }} {{ forloop.counter0 }} - {{ objective.desc }}</li>
{% endfor %}
{% else %}
<p>No objectives are available.</p>
{% endif %}
</ul>
{% endfor %}
</ul>
{% else %}
<p>No processes are available.</p>
{% endif %}
all you have to do is just pass the Process object as the context to your template
context = {'all_processes': all_processes}
and in you template :
<p>Create new Process
</p>
{% if all_processes %}
No: {{ all_processes|length }}
<ul>
{% for process in all_processes %}
<li>{{ process.title }} {{ forloop.counter0 }}</li>
<ul>
{% if all_processes.objective_set.all %}
{% for objective in all_processes.objective_set.all %}
<li>{{ objective.title }} {{ forloop.counter0 }} - {{ objective.desc }}
</li>
{% endfor %}
{% else %}
<p>No objectives are available.</p>
{% endif %}
</ul>
{% endfor %}
</ul>
{% else %}
<p>No processes are available.</p>
{% endif %}
<!-- this is if you want to show risks -->
{% for process in all_processes %}
{% for objective in all_processes.objective_set.all %}
{% for risk in objective.risk_set.all %}
{{ risk.desc }}
{% endfor %}
{% endfor %}
{% endfor %}
I hope this is what you were expecting !