文章目录
- 前言 ´・ᴗ・`
- Listview
- ListView 的细节修改
- 编辑每本书的详情页
- detailView
- 分页的编辑
- 结语( ̄︶ ̄)↗
前言 ´・ᴗ・`
- 上一节我们建立了主页 这里我们来创建一些别的网页 比如关于books author等等
- 本篇内容将会帮助你学习…
- 1 ListView的应用
- 2 DetailView的应用
Listview
就是 “列表视图” 别被名字吓到了 这是最简单的视图构建“套路”
就是在指定的数据库(类)中取出所有数据 然后列表显示出来
比如像百度那种就是典型的
还记得上节 我们是编辑过view的
像这样从数据库取数据:
num_books = Book.objects.all().count()num_instances = BookInstance.objects.all().count()num_instances_available = BookInstance.objects.filter(status__exact='a').count()num_authors = Author.objects.count() # The 'all()' is implied by default.
然后 context打包 通过render送到template那边去填空:
context = {'num_books': num_books,'num_instances': num_instances,'num_instances_available': num_instances_available,'num_authors': num_authors,'num_visits': num_visits,}# Render the HTML template index.html with the data in the context variable.return render(request, 'index.html', context=context)
不过上次有点不同 需要统计数据(多少本书什么的) 用了count()
这里 我们更加傻瓜化——直接把数据库所有书倒出来 然后一列显示就ok了
django给我们封装了这种傻瓜化的view处理 就是Listview
而且用as_view() 函数来执行
具体操作很简单
1.catalog/view.py 添加:
from django.views import genericclass BookListView(generic.ListView):model = Book
BookListView 针对数据库Book模型的ListView
- 模板编辑:
创建: /locallibrary/catalog/templates/catalog/book_list.html
{% extends "base_generic.html" %}{% block content %}<h1>Book List</h1>{% if book_list %}<ul>{% for book in book_list %}<li><a href="">{{ book.title }}</a> ({{book.author}})</li>{% endfor %}</ul>{% else %}<p>There are no books in the library.</p>{% endif %}
{% endblock %}
当然 URL映射别忘了:
urlpatterns = [path('', views.index, name='index'),path('books/', views.BookListView.as_view(), name='books'),path('authors/', views.AuthorListView.as_view(), name='authors'),]
我们可以发现
- 模板的名字 book_list.html
- 模板变量 就是那个{% for book in book_list %} 引用的book_list 这个变量
奇怪不?我们从来没定义过 怎么就能用了呢?
这就是ListView帮我们干的事 当然也约定 模板名字与模板变量都采用model那个类的名字+list
class book ->book_list
ListView 的细节修改
事实上 是一个函数为get queryset 做了 从数据库拿数据到view的工作
因此 我们通过修改这个函数 自然也可以控制输出的结果‘
实现这点 ’
- 可以从前端搞定 前端js当然可以限制 动态输出
- 也可以后端限制 通过django支持的模板的一些分支语句(if else)
- 还可以源头上 数据库调用的时候就减少数据传输
这里更改get queryset算是第三种方式 举例:
class BookListView(generic.ListView):model = Bookpaginate_by = 4def get_queryset(self):return Book.objects.filter(title__icontains='ryan')[:5] # Get 5 books containing the title war
筛选所有title包含ryan的数据记录 然后返回给render
另外 paginate_by = 4
限制了一页中显示最大的记录条数
类似sql的LIMIT BY
然后这里我们就可以runserver一下啦:
编辑每本书的详情页
我们只是作了个书的清单 但是详情页还没弄
这里 先把book_list.html 修改一下
{% for book in book_list %}<li><a href="{{ book.get_absolute_url }}">{{ book.title }}</a> ({{book.author}})</li>{% endfor %}
主要是超链接的内容加上了
然后我们大胆的添加书本的详情页 url映射
urlpatterns = [path('', views.index, name='index'),path('books/', views.BookListView.as_view(), name='books'),path('authors/', views.AuthorListView.as_view(), name='authors'),path('book/<int:pk>', views.BookDetailView.as_view(), name='book-detail'),path('author/<int:pk>', views.AuthorDetailView.as_view(), name='author-detail'),]
author的套路相同 一并添加了:)
这里 <> 就类似正则表达式 捕获url地址中 author/
后面所有的数字 并且存到pk
这个变量里面
如果url捕获参数的模式(pattern) 很复杂 欢迎使用re_path() 函数代替path() 并且使用re正则表达式
这里限于篇幅不讲了 网上有关教程很多
我们应用repath 可以这么写:
re_path(r'^book/(?P<pk>\d+)$', views.BookDetailView.as_view(), name='book-detail'),
注意path()不采用·正则 其语法规则很简单 功能很弱
re_path()是完全用正则表达式的 功能无敌强
detailView
ListView特别适合 大致列个表 这种应用 目录菜单什么的
然而detailview提供一个适合“详情页”的布局视图
非常类似ListView 你只需在catalog/view.py 中添加:
class BookDetailView(generic.DetailView):model = Book
同样 book_detail 作为模板的文件名称:
不过模板变量变成model的类名 book
在catalog/templates/catalog/book_detail.html 填写:
{% extends "base_generic.html" %}{% block content %}<h1>Title: {{ book.title }}</h1><p><strong>Author:</strong> <a href="">{{ book.author }}</a></p> <!-- author detail link not yet defined --><p><strong>Summary:</strong> {{ book.summary }}</p><p><strong>ISBN:</strong> {{ book.isbn }}</p> <p><strong>Language:</strong> {{ book.language }}</p> <p><strong>Genre:</strong> {% for genre in book.genre.all %} {{ genre }}{% if not forloop.last %}, {% endif %}{% endfor %}</p> <div style="margin-left:20px;margin-top:20px"><h4>Copies</h4>{% for copy in book.bookinstance_set.all %}<hr><p class="{% if copy.status == 'a' %}text-success{% elif copy.status == 'm' %}text-danger{% else %}text-warning{% endif %}">{{ copy.get_status_display }}</p>{% if copy.status != 'a' %}<p><strong>Due to be returned:</strong> {{copy.due_back}}</p>{% endif %}<p><strong>Imprint:</strong> {{copy.imprint}}</p><p class="text-muted"><strong>Id:</strong> {{copy.id}}</p>{% endfor %}</div>
{% endblock %}
注意“book.bookinstance_set”
首先 book 与 bookinstance 是外键 而且是一对多的
我们这里在book这端 用“一”引用多 就用了book.bookinstance_set 这是django给我们封装好的
分页的编辑
我们之前通过paginate_by = 10 进行分页 但这只是源头上限制了数据 但不能实现“前一页”“后一页”的按钮等
django封装了这个
由于我们几乎所有网页都这样式 我们直接在base_generic 更改:
打开 /locallibrary/catalog/templates/base_generic.html
{% block content %}{% endblock %}{% block pagination %}{% if is_paginated %}<div class="pagination"><span class="page-links">{% if page_obj.has_previous %}<a href="{{ request.path }}?page={{ page_obj.previous_page_number }}">previous</a>{% endif %}<span class="page-current">Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.</span>{% if page_obj.has_next %}<a href="{{ request.path }}?page={{ page_obj.next_page_number }}">next</a>{% endif %}</span></div>{% endif %}
{% endblock %}
-
page_obj 是一个 Paginator 对象,如果在当前页面上使用分页 如paginate_by = 10 ,它将启动
这玩意允许您获取有关当前页面,之前页面,有多少页面等的所有信息。 -
{{ request.path }}可用来获取用于创建分页链接的当前页面URL。
另外 我们顺便把author的也弄了:
模板 template/catalog/author_detail.html:
{% extends "base_generic.html" %}{% block content %}<h1> {{ author.first_name }}.{{author.last_name}}</h1><p><strong>living:</strong> {{ author.first_name }}.{{ author.last_name }} ({{ author.date_of_birth }}-{{ author.date_of_death }})</p><div style="margin-left:20px;margin-top:20px"><h4>What this poor bastard wrote:</h4><ul>
<!-- 这里反向查找 ‘多’引用‘一’ 而不像之前的 ‘一’引用‘多’ -->{% for copy in author.book_set.all %}<li><a href="">《{{copy.title}}》 ISBN:{{copy.isbn}}</a></li>{% endfor %}</ul></div>
{% endblock %}
模板 template/catalog/author_list.html:
{% extends "base_generic.html" %}{% block content %}<h1>Author List</h1>{% if author_list %}<ul>{% for author in author_list %}<li><a href="{{ author.get_absolute_url }}">{{ author.first_name }}.{{ author.last_name }}</a></li>{% endfor %}</ul>{% else %}<p>There are no one.</p>{% endif %}
{% endblock %}
catalog/view.py 添加
class AuthorListView(generic.ListView):model = Authorpaginate_by = 5class AuthorDetailView(generic.DetailView):model = Author
结语( ̄︶ ̄)↗
runserver检验战果
不出意外 你将收获:
到这里 基本上很多页面都能搞定了
下一站 我们会聊聊 会话
服务端编程(十一)- Django - session 认识会话 cookies
这是软菜鸡的其他系列学习文章 希望能够帮到你 ( •̀ ω •́ )✧
-
想学习数据库嘛? 不妨从MySQL入手
MySQL专栏 -
python这么火 想要深入学习python 玩一下简单的应用嘛?可以看我专栏 还在持续更新中哦:
python应用 -
这是本服务端编程专栏
手把手带你学服务端 -
谢谢大佬支持!