0

I have book template which display more info about the book like title,price and author etc..

in the same template I've similar books section where I want to display similar book to the featured book according to the classification (both have the same classification)

and to do that i'm thinking of shuffling books i retrieve from the database instead of just using normal loop to make it more dynamic as in every book has that classification, the page shows different books not the same books every time

here's the code in views.py

def book(request, book_id):
book = get_object_or_404(Book, pk=book_id)
similar_books = Book.objects.all()[:4]

book_context = {
    'book': book,
    'similar_books': similar_books
}
return render(request, 'books/book.html', book_context)

and this the the code in my template

<div class="row">
            <div class="col py-5 text-center">
                <h3 class="mb-5">Similar books</h3>
                <div class="row d-flex justify-content-center">
                    {% for similar_book in similar_books %}
                        {% if similar_book.classification == book.classification and similar_book.id > book.id %}
                            <div class="col-md-3">
                                <a href="{% url 'book' similar_book.id %}"><img src="{{ similar_book.img.url }}"></a>
                                <a href="{% url 'book' similar_book.id %}"><p class="mt-2">{{ similar_book.title}}</p></a>
                                <p class="text-muted">{{ similar_book.author }}</p>
                                <p>{{ similar_book.price }}</p>
                            </div>
                        {% endif %}
                    {% endfor %}
                </div>
            </div>

the reason i'm including similar_book.id > book.id is that i don't want it to display the featured book in its similar books

i know it's not the best way to do it with logical as if the featured book is the last book in the list, the loop will stop

i also thought of replacing the if statement above with

{% for similar_book in similar_books[{{ similar_book.id }} -1:] %} to start looping through books after the featured book and adding if statement {% if book.id == len(similar_books) %} then {% similar_book.id == 1 %}

but not sure if it's correct logical or not, any ideas?

Aya
  • 37
  • 9

2 Answers2

1

Don't put logic into your template, for example if you don't want to show the book that is being featured, you can exclude it from the queryset, like so:

def book(request, book_id):
    book = get_object_or_404(Book, pk=book_id)
    similar_books = Book.objects.all().exclude(pk=book_id)[:4]
    ...

You can get the results in the random order with the use of order_by('?'), so in the end it would look like:

def book(request, book_id):
    book = get_object_or_404(Book, pk=book_id)
    similar_books = Book.objects.all().exclude(pk=book_id).order_by('?')[:4]
    ...

Note that order_by('?') can be slow. You can read about different ways of doing the shuffling here: How to pull a random record using Django's ORM?

marke
  • 1,024
  • 7
  • 20
  • i'm pretty new to Django, i didn't know about excluding nor order_by but it worked! thanks for helping and adding new info to me :) – Aya Mar 06 '19 at 21:56
  • sure thing :) generally django has a lot of things that makes your life as a developer easy, at least when it comes to common use cases. – marke Mar 07 '19 at 00:06
0

There are a lot of similar posts to randomly get objects in Django, like this for example.

I suggest doing the suffling in your view:

id_list = list(
    Book.objects.exclude(pk=book.pk).values_list('id', flat=True))

n = 2
rand_ids = random.sample(id_list, n)
similar_books = Book.objects.filter(id__in=rand_ids)
Ralf
  • 16,086
  • 4
  • 44
  • 68