Getting limited random items from related object in templates? - python

I have an Author model with many books assigned to each one. In my Books model I have: author = models.ForeignKey(Author)
In my page, I am listing all the authors I have and under each author I want to display 5 random books.
Is this feasible through the templates only or I must do that in my view? I mean limiting the results and getting them randomly.
I'm currently only passing the authors to template, like this: a = Author.objects.all()
Please advise.

You have two options:
Do it in your view:
This query is "return 5 random books for author a"
random_books = Book.objects.filter(author=a).order_by('?')[:5]
Create a custom tag that takes an author and returns random 5 books:
Create a custom tag:
from myapp.models import Book
def randbooks(author):
return {'books': Book.objects.filter(author=author).order_by('?')[:5]}
register.inclusion_tag('book_listing.html')(randbooks)
Create a template to show the titles (book_listing.html):
<ul>
{% for book in books %}
<li>{{ book }}</li>
{% endfor %}
</ul>
Use it in your template like this:
{% for author in a %}
{% randbooks author %}
{% endfor %}

Related

How to find the children from a django queryset

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()

display model fieldnames in Django listview

In my listview I want to display several fields from two models containing a many-to-many field.
I can display the correct values from one table, but then I cannot access the other table with the many-to-manyfield.
Models.py
class Books(models.Model):
title = models.CharField(max_length=100)
class Author(models.Model):
book = models.ManyToManyField(Books)
first_name = models.CharField(max_length=150)
last_name = models.CharField(max_length=200)
Views.py
class BooksListView(ListView):
context_object_name = 'booklist'
model = Author
template_name = 'Books/books_list.html'
Book_list.html
{% for books in booklist %}
<h5><li class="list-group-item list-group-item-light"">
{{books.book.all}}:{{books.first_name}} {{books.last_name}}</li></h5>
{% endfor %}
The first and lastname are displayed properly, but the books.book.all ()i know this is the wrong query) returns a queryset containing the title (which is what I need, but this is in format <QuerySet [<Books: Book Title>]>. But books.book.title doesnt seem to work. What I want to display is "booktitle - firstname lastname", and because I am using two tables, I need a many-to-many relationship. Any thoughts?
The many-to-many relationship goes both ways, so you don't need to base everything around authors.
class BooksListView(ListView):
context_object_name = 'booklist'
model = Book
template_name = 'Books/books_list.html'
And the template:
{% for books in booklist %}
<li class="list-group-item list-group-item-light">
<h5>{{ book.title }}</h5>
<p>
{% for author in book.author_set.all %}
{{ author.first_name }} {{ author.last_name }}{% if not forloop.last %}, {% endif %}
{% endfor %}
</p>
</li>
{% endfor %}
Notes:
By default, the related_name is {{ModelName}}_set (author_set in this case). If you want something more natural you can set related_name='authors'.
There will be a query made to the databse for every book in the list and this can be quite slow with a lot of data, so take a look at prefetch_related().

querying foreignkey nested for loop django

I am trying to return a list of categories for a business, and for each category I would like to list all the items related to the category.
I was returning all of my items, not by category, but I have decided I want them sorted by category. This is what I have tried (among other attempts as well) I simply am having trouble getting the items into there categories. This is my latest attempt
In my models.py I have
Business(models.Model):
name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
logo = models.CharField(max_length=300)
ItemCategory(models.Model):
name = models.CharField(max_length=50)
Item(models.Model):
name = models.CharField(max_length=100)
business = models.ForeignKey(Business)
category = models.ForeignKey(ItemCategory)
short_description = models.CharField(max_length=250)
in my views.py
def business_profile(request, business_id):
items = Item.objects.filter(business_id = business_id).select_related('itemcategory')
return render(request, 'business_profile.html', {"items": items})
in my template I am trying
{% for itemcategory in items.itemcategory_set.all %}
{{ itemcategory.name }}
{% for item in itemcategory %}
{{ item.name }} <br>
{{ item.short_description }}
{% endfor %}
{% endfor %}
From my research into other questions and reading the documents, i felt this would be right.. However from my results I can not get the correct output in my template.
Would this be the correct practice? Or should I try getting the categories first with
categories = ItemCategory.objects.filter(business = business_id)
and then possibly add a select_related('item') to process all the items for the category?
When I refer to data in the template but my model has 2 words (ItemCategory) - for instance when I move backward for a foreign key or use the model in select_related('') - would I use item_category or do you simply use itemcategory with no underscore?
UPDATE: I answered below in comment with explanation.
To list the items by category, I used #yusuf.oguntola's idea and initially got the business with .get(), then I created a queryset to get all the items. My function in views.py included
business = Business.objects.get(id = business_id)
items = business.item_set.all().order_by('category')
note: the business_id was passed in url pattern
However, the key change was in my template. I found this awesome built in functionality for templates in the django documents here
I implemented it in template like so...
{% regroup items by category as category_list %}
<ul>
{% for category in category_list %}
<li>{{ category.grouper }}
<ul>
{% for item in category.list %}
<li>{{ item.name }}<br> {{ item.short_description }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
One of the most important parts is you have to have order_by() and put the parameter of the field you are ordering by - in my case, category. If this is not included, it will simply put the items listed in chronological order and will repeat your field instance.
items = Item.objects.filter(business_id = business_id) is wrong.
You should rather say:
items = Item.objects.filter(business__id = business_id) #Notice the double underscore.
You may also rather get the business and simply say:
business.item_set.all() #This would retrieve all Item for the business.
select_related() expects a fieldname as a paramter. So use a field name that exists on the Item model. Like:
select_related('category')
Where's the meal? May be you can proceed from there though.

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 %}

Getting spesific data from three models in django

I am starting working with django and i want get specific data from three related models.
my models are
class Institution(models.Model):
name = models.CharField(max_length=100, unique=True)
...
class Certification(models.Model):
name = models.CharField(max_length=100)
...
class Course(models.Model):
name = models.CharField(max_length=100)
institution = models.ForeignKey(Institution)
certification = models.ForeignKey(Certification)
in my html page i want display the courses offered by a particular institution ordered by certification. like this
name of a particular institution I
certification 1
list courses that offer certification 1
certification 2
list courses that offer certification 2
...
my current template is
{{institution.name}}
{% for certification in preselected_certifications %}
<h1> {{ certification.name }} </h1>
<ul>
{% for course in courses %}
<li>{{ course.name }}</li>
{% endfor %}
</ul>
{% endfor %}
my view
def detail(request, slug):
context = RequestContext(request)
context_dict = {'slug_requested': slug}
try:
institution = Institution.objects.get(slug=slug)
courses = Course.objects.filter(etablissement=etablissement)
context_dict['courses'] = courses
context_dict['institution'] = institution
except Institution.DoesNotExist:
pass
return render_to_response('institutition/details.html', context_dict, context)
my question is how define "preselected_certifications" so it contains only certifications offered by all courses in the selected institution, but without repeating any certification
Question:
how define "preselected_certifications" so it contains only certifications offered by all courses in the selected institution, but without repeating any certification
I don't know exactly how you want to represent this information (meaning, which attributes you want available), but think you want something like the following:
def detail(request, slug):
...
institution = Institution.objects.get(slug=slug)
# `select_related` not strictly necessary
courses = institution.course_set.all().select_related('certification')
context_dict['courses'] = courses
context_dict['institution'] = institution
Now, each course object will have access to its certification relation and you could iterate through them to display the unique ones.
However, if you want to ensure from the outset these certifications are unique, one way to do that is with another query:
institution = Institution.objects.get(slug=slug)
courses = institution.course_set.select_related('certification')
certification_ids = courses.values_list('certification_id', flat=True).distinct()
preselect_certifications = Certification.objects.filter(id__in=certification_ids)
That last query will get you the unique certifications for a particular institution.
It seems like Certification should potentially have a relationship to Institution, though, no?
yeah thanks a lot, now i use in my template the following code
{% for certification in preselect_certifications %}
{{certification.name}}
{% for course in courses %}
<ul>
{% if certification = course.certification %}
<li>{{ course.name }}</li>
{% endif %}
</ul>
{% endfor %}
{% endfor %}
it works perfectly, but is there another way to avoid using
{% if certification = course.certification %}
?
thanks again

Categories