Я знаю, что вы пометили ответ как правильный, но это действительно не правильный ответ согласно моим комментариям под ним. @wfehr дает вам лучшее решение, хотя это очень короткий ответ, и, основываясь на вашем вопросе, я подозреваю, что вам нужно больше подробностей.
class Book(models.Model):
title = models.CharField(max_length=300)
author = models.CharField(max_length=100)
year = models.IntegerField()
genre = models.ForeignKey('Genre', on_delete=models.CASCADE)
class Genre(models.Model):
title = models.CharField(max_length=20)
С вашими моделями все в порядке, однако их можно улучшить следующими способами :
в изменении класса Book
:
class Book(models.Model):
...
genre = models.ForeignKey('Genre', on_delete=models.CASCADE, related_name="books")
...
Добавив это связанное имя, вы сможете выполнить обратный поиск, используя Genre
, например:
myGenre.books.all()
Это дало бы вам все книги в этом жанре.
В любом случае, я отвлекся.
В вашем View.py
, который возвращает шаблон, а не тот лог c в вашем шаблоне согласно ответу, который вы пометили как правильный, просто отфильтруйте установленный там запрос для точной информации, которую вы хотите отобразить.
Я полагаю, что в настоящее время у вас есть что-то похожее на это в ваш взгляд:
render("template.html", {genres=Genre.objects.all()})
вместо Genre.objects.all()
, используйте Book
и наоборот Book
:
Book.objects.order_by('-genre').filter(year__gte=1950)
Таким образом, вы получите только те книги, которые вам действительно нужны. gte
«больше или равно»; если вы хотите просто после 1950 года, измените его на year__gt
.
Кроме того, если вам нужны только название и жанр книги, которые вы можете сделать:
Book.objects.order_by('-genre').filter(year__gte=1950).values_list("title", pk)
Вы используете только заголовок, но вы можете указать любое поле модели.
Решение, приведенное выше, не разбивает его на Genre
с, поэтому вам нужно сделать немного больше. Вы можете сделать это с помощью annotate
вместо списка значений , читая здесь , или вы можете сначала просто выбрать жанры и сделать следующее:
(Примечание: использование annotate
уменьшит БД обращается к 1, но в зависимости от количества жанров это может не быть проблемой:
books = {}
for genre in Genre.objects.all().order_by('-title'):
books[genre.title] = Book.objects.order_by('-genre').filter(year__gte=1950, genre=genre).values_list("title")
Использование order_by('-title')
просто гарантирует, что мы получим некоторый порядок в жанрах - в данном случае по алфавиту.
Затем вы можете просто вернуть context=books
или добавить его к текущему объекту контекста, а затем настроить свой шаблон соответственно следующим образом:
{% for key, values in books.items %}
<h1> {{key}} </h1>
{% for book in values %}
{{book}}
{% endfor %}
{% endear%}
Делая это таким образом, вы не запрашиваете БД для каждой книги, и вы не фильтруете в шаблоне.
Еще одна вещь до I go, если вы не планируете разрешать пользователям добавлять жанры, то есть они предопределены, вы может покончить с моделью Genre
, полностью меняя поле genre
на модели Book
для простого
genres = (
("scf", "SciFi)",
("hrr", "Horror"),
("rom","Romance"),
("gen", "General"),
)
genre = models.CharField(choices=genres, default="gen", max_length=3)
Я добавил, что только для справки; использование модели лучше, если вам нужно добавить жанры, или если у у тебя их будет много.