Django 4.0 получение объектов поля "многие ко многим" в представлении списка

Я совсем новичок в Django и застрял в нем. У меня есть модель книги и модель жанра, которые имеют отношения "многие ко многим". Как мне получить все книги определенного жанра в виде списка. Я предполагаю, что быстрее получить объект Genre и получить все книги из него с помощью запроса типа "genre.objects.book_set.all", чем перебирать все книги и смотреть, есть ли в них указанный жанр. Однако я не уверен, как я могу сделать это в ListView? Я хочу взять название жанра из url и затем использовать его для получения объекта жанра. Вот что у меня есть

URL:

path('genre/<string:name>', GenreListView.as_view(), name='book-genre'),

Модели:

class Genre(models.Model):
name = models.CharField(max_length=50, unique=True)
def __str__(self):
    return self.name


class Book(models.Model):
name = models.CharField(max_length=150, unique=True)
description = models.TextField()
user_count = models.IntegerField()
pages = models.IntegerField()
genres = models.ManyToManyField(Genre)
image = models.ImageField(default='book_imgs/default.jpg', upload_to='book_imgs')

def __str__(self):
    return self.name

Вид?

class GenreListView(ListView):

    model = Genre

    def get_queryset(self):
Not sure what to put here....

        return 

Любая помощь будет принята с благодарностью, спасибо.

Вы можете сделать примерно следующее:

class SciFiListView(View):
    scifi_books = Book.objects.filter(genres__name__icontains="scifi")
    return render(request, "books/list.html", {"scifi_books": scifi_books})

list.html
{% for book in scifi_books %}
<p>{{ book.name }} | {{ book.description }}</p>
{% endfor %}

Вы должны передать id жанр, затем применить фильтр в методе get_queryset, чтобы получить все книги для определенных жанров следующим образом:

urls.py

path('genre/<int:id>/', GenreListView.as_view(), name='book_genre'),

views.py

class GenreListView(ListView):
    model = Book
    template_name = 'any_folder_name/any_file_name.html'
    context_object_name = 'specific_books'

    def get_queryset(self):
        qs = super().get_queryset()
        return qs.filter(genres=self.kwargs['id'])

Тогда в шаблоне можно показать книги, относящиеся к определенному жанру.

any_file_name.html

<body>
    {% for book in specific_books %}
    <div>
        <p>{{book.name}}</p>
        <p>{{book.description}}</p>
        <p>{{book.pages}}</p>

    </div>
    <br>
    {% endfor %}
</body>

Или вы можете просто сделать это с помощью представлений, основанных на функциях.

urls.py

 path('genre/<int:id>/', views.specific_books, name='specific_books'),

views.py

def specific_books(request, id):
    specific_books = Book.objects.filter(genres=id)
    return render(request, 'any_folder_name/any_file_name.html', {'specific_books': specific_books})

Редактирование:

Если вы хотите отфильтровать все книги по названию Genre, сделайте следующее:

urls.py

 path('genre/<str:name>/', views.specific_books, name='specific_books'),

views.py

def specific_books(request, name):
    specific_books = Book.objects.filter(genres__name__icontains=name)
    return render(request, 'home/index.html', {'specific_books': specific_books})

Я решил переключить представление на детальное представление вместо представления списка, и тогда с html-страницы я смогу получить доступ к книгам, связанным с этим жанром.

html:

{% for book in genre.book_set.all %}
        <li>{{ book.name }}</li>
    </a>
    {% endfor %}

view:

class GenreDetailView(DetailView):
    model = Genre
    context_object_name = "genre"

модель:

class Genre(models.Model):
    name = models.CharField(max_length=50, unique=True)
    slug = models.SlugField(null=True, unique=True)

def __str__(self):
    return self.name

def get_absolute_url(self):
    return reverse("book-genre", kwargs={"slug": self.slug})

def save(self, *args, **kwargs): 
    if not self.slug:
        self.slug = slugify(self.name)
    return super().save(*args, **kwargs)

Url:

path('genre/<slug:slug>', GenreDetailView.as_view(), name='book-genre'),

Я считаю, что это лучше, чем просматривать каждую книгу и проверять, есть ли в ней жанр, который вы ищете.

Вернуться на верх