对于Django模板{%url%}标记,如何从通用视图上下文中找到所有URL参数,而不仅仅是最后一个?

时间:2018-03-07 16:32:58

标签: python django django-templates django-urls

在Django中,我正在尝试创建一个具有模型树层次结构的应用程序,即 Books 包含 Chapters ,其中包含 Sections 等。我想要我的镜像结构的网址,例如 books / 3 / chapter / 5 / sections

我想使用基于类的通用视图。在我的HTML模板中,我将使用 {%url%} 命令指定链接目标。

对于结构深处的网址,我需要提供 {%url%} 以及网址中显示的所有密钥。对于上面的示例: {%url' pattern-name' 3 5%}

但是,基于类的通用视图仅在模板上下文中提供(如果是)它们所关注的对象的主键(即,在上面:5中)。

如何检索父对象的外键(即上面的:3)?

我有以下内容:

我的模特 的 models.py:

class Book(models.Model):
  name = models.CharField("Book Name", max_length = 80)

class Chapter(models.Model):
  name = models.CharField("Book Name", max_length = 80)
  book = models.ForeignKey('Book', on_delete = models.CASCADE)

urls.py中的网址格式:

urlpatterns = [
  path('books/', 
       views.BookListView.as_view(), name='book_list'),
  path('books/<int:book>/', 
       views.BookDetailView.as_view(), name='book_detail'),
  path('books/<int:book>/chapters/', 
       views.ChapterListView.as_view(), name='chapter_list'),
  path('books/<int:book>/chapters/<int:chapter>/',
       views.ChapterDetailView.as_view(), name='chapter_detail'),
  path('books/<int:book>/chapters/create/',
       views.ChapterCreateView.as_view(), name='chapter_create'),

views.py中的观点

class BookListView(generic.ListView):
  model = 'Book'

class BookDetailView(generic.DetailView):
  model = 'Book'
  pk_url_kwarg = 'book'

class ChapterListView(generic.ListView):
  model = 'Chapter'
  def get_queryset(self):
    return Chapter.objects.filter(book = self.kwargs['book'])

class ChapterDetailView(generic.DetailView):
  model = 'Chapter'
  pk_url_kwarg = 'chapter'

class ChapterCreateView(generic.CreateView):
  model = 'Chapter'
  fields = ['name', 'book']
  def get_initial(self):
    initial = super().get_initial().copy()
    initial['book'] = self.kwargs.['book']
    return initial;

在用于章节列表的HTML模板中,我希望有一个链接来创建新的章节。目前,该模板如下所示:

模板 chapter_list.html:

<ul>
{% for chapter in chapter_list %}
  <li>{{ chapter.name }}</li>
{% endfor %}
</ul>
<a href="{% url 'chapter_create' 42 %}">Add new chapter</a>

显然,我不想将所有新章节添加到ID 42 的书中,而是希望使用章节列表中的书籍ID,我所在的位置。例如,对于URL

.../books/17/chapters/create/

我希望链接指向:

<a href="{% url 'chapter_create' 17 %}">Add new chapter</a>

我发现动态执行此操作的唯一方法是在章节列表视图中添加额外的上下文:

更新了 views.py:

...

class ChapterListView(generic.ListView):
  model = 'Chapter'
  def get_queryset(self):
    return Chapter.objects.filter(book = self.kwargs['book'])

  # Additional Context
  def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    context['my_current_book_id'] = self.kwargs['book']
    return context

...

然后让模板说:

更新了 chapter_list.html:

<ul>
{% for chapter in chapter_list %}
  <li>{{ chapter.name }}</li>
{% endfor %}
</ul>
<a href="{% url 'chapter_create' my_current_book_id %}">Add new chapter</a>

这是我的问题:

有没有更简单的方法(即更多的Django-ish内置)方法来做到这一点?

在我看来,这必须是一个非常普通的任务,并且通过通用视图类和URL(反向)查找的漂亮和细粒度设计,我必须遗漏一些东西。

2 个答案:

答案 0 :(得分:2)

我会考虑为get_absolute_urlbook_detail定义chapter_detail,为chapter_create等其他网址定义额外的方法:

class Book(models.Model):
    name = models.CharField("Book Name", max_length = 80)

    def get_absolute_url(self):
        return reverse('book_detail', args=[self.pk])

    def get_create_chapter_url(self):
        return reverse('chapter_create', args=[self.pk])


class Chapter(models.Model):
    name = models.CharField("Book Name", max_length = 80)
    book = models.ForeignKey('Book', on_delete = models.CASCADE)

    def get_absolute_url(self):
        return reverse('chapter_detail', args=[self.book_pk, self.pk])

然后在模板中,您可以使用{{ chapter.get_absolute_url }}{{ book.get_absolute_url }}{{ chapter.book.get_create_chapter_url }}等,而且您不必担心网址中的参数。

在章节详细信息视图中,您可以使用外键访问Book模型上的方法:

{{ chapter.book.get_absolute_url }}

在章节列表视图中,您需要将书籍添加到上下文中(如果书中没有章节):

from django.shortcuts import get_object_or_404

class ChapterListView(generic.ListView):
    model = 'Chapter'

    def get_queryset(self):
        return Chapter.objects.filter(book = self.kwargs['book'])

  def get_context_data(self, **kwargs):
      context = super().get_context_data(**kwargs)
      context['book'] = get_object_or_404(pk=self.kwargs['book'])
      return context

然后您可以在上下文中访问{{ book }}

或者您可以使用DetailView模型查看章节列表视图:

Book

然后class ChapterListView(generic.DetailView): model = 'Book' pk_url_kwarg = 'book' 已经在模板上下文中,您可以通过以下方式遍历相关章节:

book

顺便说一句,在创建视图中省略{% for chapter in book.chapter_set.all %} {{ chapter }} {% endfor %} 字段可能更简单。然后在保存表单之前在book方法中设置它。

form_valid

答案 1 :(得分:0)

您可以使用Book作为模型的视图:

{% for chapter in book.chapter_set.all %}