需求
- 基于ListView,创建一个列表视图,用于展示"BookInfo"表的信息
- 要求提供分页
- 提供对书名,作者,描述的查询功能
示例展示:
1. 数据模型
python
class BookInfo(models.Model):
title=models.CharField(verbose_name="书名",max_length=100)
author=models.CharField(verbose_name="作者",max_length=100)
desc=models.TextField(verbose_name="介绍")
create_at=models.DateTimeField(verbose_name="创建时间",auto_now=True)
update_at=models.DateTimeField(verbose_name="更新时间",auto_now_add=True)
2. 视图
python
from functools import reduce
from typing import Any
from django.shortcuts import render,redirect
from django.db.models import Q
from django.views.generic import ListView
from django.views.generic.detail import DetailView
from .models import *
from .forms import *
class BookListView(ListView):
model=BookInfo
template_name = "demo1/book_list.html"
paginate_by = 10
def get_queryset(self):
title = self.request.GET.get('title')
author = self.request.GET.get('author')
content = self.request.GET.get('content')
# 如果有任意参数不为空,则构建Q对象进行查询
queries = [Q(titile__icontains=title) if title else Q(),
Q(author__icontains=author) if author else Q(),
Q(desc__icontains=content) if content else Q()]
# 使用Q对象的&操作符组合查询条件
queryset = BookInfo.objects.filter(reduce(lambda x, y: x & y, queries)) if queries else BookInfo.objects.all()
return queryset
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# 保留查询参数到分页链接
query_params = self.request.GET.copy()
if 'page' in query_params:
del query_params['page'] # 移除现有的页码参数以避免冲突
paginator = context['paginator']
page_numbers_range = 5 # 您可以根据需要调整显示的页码范围大小
max_index = len(paginator.page_range)
page = self.request.GET.get('page')
current_page = int(page) if page else 1
start_index = int((current_page - 1) / page_numbers_range) * page_numbers_range
end_index = start_index + page_numbers_range
if end_index >= max_index:
end_index = max_index
page_range = paginator.page_range[start_index:end_index]
context['page_range'] = page_range
context['query_params'] = query_params.urlencode() # 将查询参数编码为URL字符串
return context
def get(self, request, *args, **kwargs):
# 如果是重定向回来的,需要处理paginate_by参数
if 'paginate_by' in request.GET:
try:
paginate_by = int(request.GET['paginate_by'])
if paginate_by > 0: # 防止不合法的值
self.paginate_by = paginate_by
except ValueError:
pass # 如果转换失败,忽略错误,使用默认设置
return super().get(request, *args, **kwargs)
class BookDetailView(DetailView):
model=BookInfo
template_name = "demo1/book_detail.html"
context_object_name = "book"
注册路由(urls.py)
from django.urls import path
from .views import *
urlpatterns = [
path("book",BookListView.as_view(),name="book-list"),
path("book/detail/<int:pk>/",BookDetailView.as_view(),name="book-detail"),
]
3. 页面代码
列表页:
html
{% extends 'layout.html' %}
{% block main %}
<div class="panel panel-default">
<div class="container">
<form method="GET">
检索:
<input type="text" name="title" placeholder="书名" value="{{ request.GET.title }}">
<input type="text" name="author" placeholder="作者" value="{{ request.GET.author }}">
<input type="text" name="content" placeholder="内容关键字" value="{{ request.GET.content }}">
<button type="submit">搜索</button> <a href="{% url 'book-list' %}" class="btn-sm btn-danger">清空查询条件</a>
</form>
</div>
<hr>
<div class="panel-body">
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>书名</th>
<th>作者</th>
<th>说明</th>
<th>创建时间</th>
<th>更新时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for book in object_list %}
<tr>
<td>{{ book.id }}</td>
<td>{{ book.titile }}</td>
<td>{{ book.author }}</td>
<td>{{ book.desc }}</td>
<td>{{ book.create_at }}</td>
<td>{{ book.update_at }}</td>
<td><a href="{% url 'book-detail' book.id %}">查看详情</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% if is_paginated %}
<div class="pagination">
<p>第 {{ page_obj.number }} 页 / 共 {{ page_obj.paginator.num_pages }} 页</p>
<!-- 首页 -->
{% if page_obj.has_previous %}
<a href="?{{ query_params }}&page=1">首页</a>
{% endif %}
<!-- 上一页 -->
{% if page_obj.has_previous %}
<a href="?{{ query_params }}&page={{ page_obj.previous_page_number }}">上一页</a>
{% endif %}
<!-- 中间页码,显示首末3页及当前页附近的页码,其余用省略号表示 -->
{% for num in page_obj.paginator.page_range %}
{% if num == page_obj.number %}
<span>{{ num }}</span> <!-- 当前页不做成链接 -->
{% elif num >= page_obj.number|add:-2 and num <= page_obj.number|add:2 %}
<a href="?{{ query_params }}&page={{ num }}">{{ num }}</a>
{% elif num in page_obj.paginator.page_range|slice:":3" or num in page_obj.paginator.page_range|slice:"-3:" %}
<a href="?{{ query_params }}&page={{ num }}">{{ num }}</a> <!-- 确保首末3页始终显示 -->
{% elif num == page_obj.number|add:-3 or num == page_obj.number|add:3 %}
<span>...</span>
{% endif %}
{% endfor %}
<!-- 下一页 -->
{% if page_obj.has_next %}
<a href="?{{ query_params }}&page={{ page_obj.next_page_number }}">下一页</a>
{% endif %}
<!-- 尾页 -->
{% if page_obj.has_next %}
<a href="?{{ query_params }}&page={{ page_obj.paginator.num_pages }}">尾页</a>
{% endif %}
<!-- 当前页及总页数信息 -->
<!-- 跳转到指定页的表单 -->
<label for="jumpToPage">跳转到页数:</label>
<input type="number" id="jumpToPage" min="1">
<button onclick="jumpToPage()">跳转</button>
</div>
</div>
{% endif %}
</div>
<script>
function jumpToPage() {
var jumpTo = document.getElementById('jumpToPage').value;
var currentQueryParams = new URLSearchParams(window.location.search);
if (jumpTo.trim() !== '') { // 确保输入有效
// 保留现有查询参数,并添加或更新'page'参数
currentQueryParams.set('page', jumpTo);
window.location.href = window.location.pathname + '?' + currentQueryParams.toString();
} else {
alert('请输入有效的页数');
}
}
</script>
{% endblock %}
详情页(略)