How to find the children from a django queryset - python

I have two django models One for blog pages and one for the blog listing: a list of all blogs. The blogpage has a ForeignKey reference to the listing page.
class BlogListingPage(Page):
...
class BlogDetailPage(Page):
blog_listing = models.ForeignKey(BlogListingPage,
on_delete=models.PROTECT,
blank=True,
null=True,
related_name='+',)
In views.py I have tried to look at the queryset object, but I cannot find a refernce to the detail pages.
def blog(request):
context = {'data': BlogListingPage.objects.all()}
query_set = context['data']
for item in query_set:
print(item.__dict__)
It does correctly tell me the number of detail pages in numchild
How can I access the children themselves?
[EDIT]
I have looked at the answer to this question but it doesn't tell us how to generate event_set
{% for blog_listing in data %}
<h2>{{ blog_listing.blog_listing_title }}</h2>
{% for post in blog_listing.blogdetailpage %}
{{ post.blog_title }}
{% endfor %}
{% endfor %}

You can access related objects in this way:
item.blogdetailpage_set.all()

Related

Is it possible to filter "Related field" in Django Template?

I am developing an Instagram clone using Django. I wanted to show the latest two comments for each post.
As of now, I am only able to show all comments using the below code
home.html
{% for comment in post.comments.all %}
<p>{{ comment.user.username }}: {{ comment.description }}</p>
{% endfor %}
My models
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post_linked = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
description = models.CharField(max_length=500)
comment_posted_on = models.DateTimeField(default=timezone.now)
def __str__(self):
return "Comment by {} on {}".format(self.user.username, self.post_linked.caption)
Is there any way I cal display only the Latest two comment for each post?
You should create the collection of filtered comments in your view, then include that in the template's context. Django's template philosophy is to make them as simple as possible which generally means no function calls (except for template tags and filters).
To make things a bit more efficient you should utilize prefetch_related and Prefetch. Checkout the docs on them for the best reference.
from django.db.models import Prefetch
posts = Post.objects.all().prefetch_related(
Prefetch(
'comments',
Comment.objects.select_related('user').order_by('-comment_posted_on')[:2],
to_attr='latest_comments',
)
)
Then in your template:
{% for comment in post.latest_comments %}
<p>{{ comment.user.username }}: {{ comment.description }}</p>
{% endfor %}
The django templatetag "slice" will help you out here:
https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#slice
With your code:
{% for comment in post.comments.all|slice:":2" %}
<p>{{ comment.user.username }}: {{ comment.description }}</p>
{% endfor %}
This assumes your model for comments is ordered by most recent first. You might need to add that to class Meta for the Comment model.

How do you get queryset objects related to queryset passed to templates in Django

I have these two models and as you can see they have a relationship.
class Post(models.Model):
text = models.TextField()
class PostImage(models.Model):
post = models.ForeignKey(Post, default=None, on_delete=models.CASCADE)
image = models.FileField(upload_to = 'media/',blank=True, null=True)
As far as I understand if I query posts and push them to a template and post, I would expect to use something like this in my templates to retrieve the images URL attached to the posts but it doesn't seem to work.
{% for post in posts %}
{% for post_image in post.post_image_set.all %}
{{post_image.image.url}}
{% endfor %}
{% endfor %}
What am I doing wrong?
Here is my views.py file.
views.py
# Create your views here.
def index(request):
posts=Post.objects.filter(approved=True).order_by('-published_date')
context = {"posts":posts}
return render(request, 'post/home.html',context)
The default related name for a foreign key relational is the name of the model (PostImage) but in your template for loop you called it post_image Following relationships “backward”
change
{% for post_image in post.post_image_set.all %}
into
{% for post_image in post.postimage_set.all %}
Template code (with change)
{% for post in posts %}
{% for post_image in post.postimage_set.all %}
{{post_image.image.url}}
{% endfor %}
{% endfor %}

How do I filter a model in html django

I'm trying to filter a model in HTML I know that you can use eg. Model.objects.filter(bla=bloo, ...).
I wanna do that in HTML not in my views.py.
my model looks like this:
class Like(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="likeUser")
post = models.ForeignKey(NewPost, on_delete=models.CASCADE)
heres my views.py:
posts = NewPost.objects.all()
like = Like
return render(request, "network/index.html", {
"posts": posts,
"like": like
)}
heres what I'm trying to do in HTML:
{% for post in posts %}
{{ like.objects.filter(post=post) }}
{% endfor %}
I'm getting an error right now saying: Could not parse the remainder: '(post=post)' from 'like.objects.filter(post=post)'
How can I make it work?
According to the docs, a reverse relation is created by default, so you can simply do:
{% for post in posts %}
{{ post.like_set }}
{% endfor %}

How to get an ManyToManyField related queryset that can be iterated in Django?

lets say my models.py looks like this:
class Tag(models.Model):
name = models.CharField(max_length=50)
class Review(models.Model):
text = models.TextField()
tags = models.ManyToManyField(Tag, related_name='review_tags', blank=True)
In my views.py I am getting a queryset like this:
def index(request):
reviews = Review.objects.all()
return render(request, 'myapp/index.html', {'reviews' : reviews})
Now in index.html, I am doing something like this:
<div>
{% for review in reviews %}
<p>{{review.text}}</p>
{% for tag in review.tags %}
{{tag.name}}
{% endfor %}
{% endfor %}
</div>
Obviously, this does not work. However, it gives you an idea of what I am trying to do, that is, get the tags for a particular review and just display them. How do I do this with my current setup?
Thank you.
I am completely rewrited the answer, because it get upvotes and 'accepted answer', however initially it was wrong.
So the right answer would be to call {% for tag in review.tags.all %} to iterate through all Tag objects that relate to Review object in loop.
Adition: if you want firstly iterate though Tag objects and then iterate through Review objects that has a relation with Tag then you need to have view, that returns Tag objects.
def index(request):
tags = Tag.objects.all()
return render(request, 'index.html', {'tags': tags})
And in the template you need to iterate using related_name in ManyToManyField
{% for tag in tags %}
<p>{{tag.name}}</p>
{% for review in tag.review_tags.all %}
{{ review.text }}
{% endfor %}
{% endfor %}

How to add custom data to Django MPTT model for recursetree template tag

This question about MPTT objects and usage of the {% recursetree %} template tag is related to this one.
My Django Model:
from mptt.models import MPTTModel, TreeForeignKey
class myModel(MPTTModel):
myIntA = models.IntegerField(default=0)
myParent = TreeForeignKey('self', null=True, blank=True, related_name='children')
My View:
myModelList = myModel.objects.all()
for i in range(len(myModelList)):
myModelList[i].myIntB = i
return render(
request,
'myApp/myTemplate.html',
Context(
{
"myModels": myModelList,
}
)
)
Is the above legal? You can see that I added a variable myIntB to each myModel object.
However when I try to print myIntB in the template below, nothing shows up.
How can I access myIntB from the template? It is not a field I have defined for this model, nor do I want it to be. I just want myModel to be augmented with this extra variable during rendering of this particular template. The problem is that I don't see anyway to do so with the recursetree template tag.
My Template:
{% load mptt_tags %}
<ul>
{% recursetree nodes %}
<li>
{{node.id}} {{node.myIntA} {{node.myIntB}}
{% if not node.is_leaf_node %}
<ul>
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
The recursetree tag calls .order_by on your queryset, if it's actually a queryset.
This copies the queryset, does another query and re-fetches all the objects from the database. Your extra attribute no longer exists on the new objects.
The easiest way to fix this is probably to call list() on your queryset before passing it to recursetree. Then mptt will assume the ordering is already done and won't re-order the queryset.
myModelList = list(myModel.objects.order_by('tree_id', 'lft'))
for i, obj in enumerate(myModelList):
obj.myIntB = i
return render(
request,
'myApp/myTemplate.html',
Context({"myModels": myModelList})
)

Categories