Django получить следующий объект, учитывая текущий объект в наборе запросов
У меня есть модель главы, и в представлении детализации главы я хочу, чтобы пользователь мог переходить к следующей и предыдущей главе, учитывая текущую главу, которую он просматривает, и каков наиболее эффективный способ сделать это в django
это моя модель главы
class Chapter(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(blank=True,null=True,)
module = models.ForeignKey(Module,on_delete=models.CASCADE,null=True,blank=True,)
content = models.TextField()
def __str__(self):
return self.title
i have seen some answers while they use the python list method to turn the queryset in to an array but i think maybe there is a better way
Я думал о пагинации, но написал самый быстрый способ.
class Chapter(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(blank=True,null=True,)
module = models.ForeignKey(Module,on_delete=models.CASCADE,null=True,blank=True,)
content = models.TextField()
def __str__(self):
return self.title
def get_next(self):
return Chapter.objects.filter(id__gt=self.id).order_by('id').first()
в HTML
Вам нужно вызвать get_next
в цикле объектов главы. Я предполагаю, что URL вашей главы выглядит как detail/<id>
<a href= {% url 'detail' obj.get_next.id }}> next chapter </a>
Вы можете предоставить их в контексте детального представления. Например, предыдущая_глава, текущая_глава и следующая_глава, как показано ниже
class ChapterDetailView(DetailView):
model = Chapter
template_name = 'chapter_detail.html'
context_object_name = 'current_chapter'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['previous_chapter'] = your_previous_chapter_link_if_any_else_none
context['next_chapter'] = your_next_chapter_link_if_any_else_none
return context
Другим подходом может быть определение урлов в models.py следующим образом
class Chapter(models.Model):
# ... your models field
def get_next_chapter_url(self):
next_chapter = Chapter.objects.filter(id__gt=self.id).order_by('id').first()
if next_chapter:
return reverse('chapter-detail', kwargs={'id': next_chapter.id})
А в шаблоне страницы детализации главы имя объекта контекста принимается как current_chapter
<a href="{{current_chapter.get_next_chapter_url}}">Next Chapter</a>
Я бы поостерегся использовать id в качестве позиционного идентификатора, поскольку это надежно только в том случае, если главы создаются последовательно - вы не можете создать один модуль глав, затем другой, затем добавить последнюю главу в первый модуль, и вы не можете переставить главы позже. Я бы расширил модель, включив в нее поле порядка, уникальное для модуля
в вашей модели
ordering = models.PositiveSmallIntegerField()
meta:
unique_together = (module, ordering) #so each module can only have one chapter with ordering of 1
Тогда вы можете определить метод get_next_chapter (аналогично работает метод get previous chapter)
class Chapter(models.Model):
... fields
def get_next_chapter_url(self):
next_chapter_index = self.ordering + 1
next_chapter = Chapter.objects.filter(module = self.module, ordering = next_chapter_index).first()
Но... хотя это будет работать, каждое обращение к нему - это еще один вызов базы данных. Для большей эффективности можно использовать порядковый номер в представлении, чтобы получить все соответствующие главы одним запросом, например:
views.py
def view_chapter(request, module_id, chap_num):
#define vars
chapters = [chap_num - 1, chap_num, chap_num + 1]
prev_chapter = None
chapter = None
next_chapter = None
#perform single query
queryset = Chapters.objects.filter(ordering__in=chapters, module_id=module_id).select_related('module')
#I've thrown selected_related in so you can use things like chapter.module.name in your template without additional database calls.
#define context vars
for chapter in queryset:
if chapter.ordering == chap_num:
chapter=chapter
elif chapter.ordering == chap_num - 1:
prev_chapter = chapter
elif chapter.ordering == chap_num + 1:
next_chapter = chapter
context = {"chapter": chapter, "prev-chapter": prev_chapter, "next_chapter": next_chapter}
и затем в вашем шаблоне
<a href="{% url 'view chapter' chapter.module_id prev_chapter.ordering %}"> previous chapter</a>