框架第十三天周总结-----图书管理系统代码优化,加分页器,加了用户注册,登录,退出登录,登录成功自动显示登录用户的用户名等功能

settings 文件相关配置
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'day14',
        'HOST': '127.0.0.1',
        'port': 3306,
        'USER': 'root',
        'PASSWORD': '222',
        'CHARSET': 'utf8'
    }
}

STATIC_URL = '/static1/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static')
]

AUTH_USER_MODEL = 'app01.UserInfo'

.
.

from django.db import models

# Create your models here.

from django.contrib.auth.models import AbstractUser

# 扩展auth_user表
class Userinfo(AbstractUser):
    phone = models.BigIntegerField(null=True)
    desc = models.TextField(null=True)


class Book(models.Model):
    """图书表"""
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32, verbose_name='书名')
    price = models.DecimalField(max_digits=9, decimal_places=3, verbose_name='价格')
    publish_time = models.DateTimeField(auto_now_add=True)

    """一对多字段"""
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)

    """多对多字段"""
    authors = models.ManyToManyField(to='Author')

    def __str__(self):
        return f'图书对象<<*>>{self.title}'


class Publish(models.Model):
    """出版社表"""
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32, verbose_name='出版社名称')
    address = models.CharField(max_length=64, verbose_name='地址')

    def __str__(self):
        return f'出版社对象<<*>>{self.name}'


class Author(models.Model):
    """作者表"""
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32, verbose_name='作者姓名')
    age = models.IntegerField(verbose_name='年龄')

    """一对一字段"""
    author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)

    def __str__(self):
        return f'作者对象<<*>>{self.name}'


class AuthorDetail(models.Model):
    id = models.AutoField(primary_key=True)
    phone = models.BigIntegerField(verbose_name='电话号码')
    address = models.CharField(max_length=64, verbose_name='作者地址')

    def __str__(self):
        return f'作者详情表对象<<*>>{self.address}'

.
.

总路由
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    # 路由分发
    path('app01/', include('app01.urls'))
]
------------------------------------------------
分路由
from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('home/', views.home_func, name='home_view'),
    # 图书列表展示页
    path('book_list/', views.book_list_func, name='book_list_view'),

    # auth用户注册
    path('register/', views.register_func, name='register_func_view'),

    # auth用户登录
    path('login/', views.login_func, name='login_func_view'),

    # auth修改密码
    path('set_pwd/', views.set_pwd_func, name='set_pwd_func_view'),

    # auth用户退出登录
    path('logout/', views.logout_func, name='logout_func_view'),

    # 图书数据添加页
    path('book_add/', views.book_add_func, name='book_add_view'),

    # 图书数据编辑页
    path('book_edit/<int:book_pk>', views.book_edit_func, name='book_edit_view'),

    # 图书删除页
path('book_delete/<int:book_pk>', views.book_delete_func,name='book_delete_view')
]

.
.

视图层代码

from django.shortcuts import render, HttpResponse, redirect, reverse

# Create your views here.
from app01 import models


def home_func(request):
    return render(request, 'homePage.html')

--------------------------------------------

from app01 import models

def register_func(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        confirm_password = request.POST.get('confirm_password')
        if not password == confirm_password:
            return HttpResponse('两次密码不一致')
        # 校验用户名是否存在
        res = models.Userinfo.objects.filter(username=username)
        if res:
            return HttpResponse('用户名已存在')
        # 注册用户(create方法不能用)
        models.Userinfo.objects.create_user(username=username, password=password)
    return render(request, 'registerPage.html')

# 这个地方因为我用的是自己扩展的auth_user表也就是Userinfo表,别忘了去settings里面声明替换关系AUTH_USER_MODEL = 'app01.UserInfo'
# 否则就要导模块,导的这个User是一个类对应的就是auth_user表!!!
# 然后用auth_user表来进行数据查询与添加
from django.contrib.auth.models import User
res = models.User.objects.filter(username=username)
User.objects.create_user(username=username, password=password)
--------------------------------------------
from django.contrib import auth

def login_func(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        # 校验用户名与密码是否正确
        user_obj = auth.authenticate(request, username=username, password=password)
        # 如果用户名与密码正确,自动生成session数据
        if user_obj:
            auth.login(request, user_obj)
            target_path = request.GET.get('next')
            if target_path:
                obj = redirect(target_path)
            else:
                obj = redirect(reverse('home_view'))
            request.session.set_expiry(2419200)
            return obj
        else:
            return HttpResponse('密码不正确')
    return render(request, 'loginPage.html')
--------------------------------------------

# 写装饰器
from django.contrib.auth.decorators import login_required


@login_required(login_url='/app01/login/')
def book_list_func(request):
# 手动加分页器代码
    per_page_num = 3  # 每页展示数据条数
    current_page = request.GET.get('page', 1)  # 按键正常拿值,拿不到就按1拿
    # 防止用户乱输要跳转的页数,异常就展示第一页
    try:
        current_page = int(current_page)
    except Exception:
        current_page = 1

    # 获取数据的总个数
    all_book_queryset = models.Book.objects.all()
    all_count = all_book_queryset.count()
    # 获取页面的总个数
    all_page_num, yushu = divmod(all_count, per_page_num)
    if yushu:
        all_page_num += 1

    html_str = ''
    xxx = current_page
    yyy = current_page
    if xxx < 6:
        xxx = 6
    if yyy > all_page_num - 5:
        yyy = all_page_num - 5

    # 注意这个地方玩的很骚,用变量名xxx指代current_page来控制分页的标签的个数与标签显示的样式,这地方分页标签的个数展示还有点问题(这个地方逻辑有点烦)
    for i in range(xxx - 5, yyy + 6):
        # 下面用还用current_page变量名来控制用户实际点的是哪一页,就将该分页显示选中
        if current_page == i:
            html_str += '<li class="active"> <a href="?page=%s">%s</a></li>' % (i, i)
        else:
            html_str += '<li> <a href="?page=%s">%s</a></li>' % (i, i)
    # 每次for循环产生一个新的分页标签的代码的字符串,和原来的字符串进行一个拼接,
    # 最后结束,所有的标签代码的字符串都拼接在一起,被html_str变量接收,传给html,利用过滤器 |safe 解析出代码

    start_num = (current_page - 1) * per_page_num  # 起始展示位置
    end_num = current_page * per_page_num  # 终止展示位置

    part_book_queryset = all_book_queryset[start_num:end_num]

# 手动加分页器代码
    # book_queryset = models.Book.objects.all()  原来这行代码就不能要了!!!
    # 现在传给页面的是 part_book_queryset
    return render(request, 'bookListPage.html', locals())

--------------------------------------------
@login_required(login_url='/app01/login/')
def set_pwd_func(request):
    if request.method == 'POST':
        old_pwd = request.POST.get('old_pwd')
        new_pwd = request.POST.get('new_pwd')
        confirm_pwd = request.POST.get('confirm_password')
        print(new_pwd)
        print(confirm_pwd)

        if not new_pwd == confirm_pwd:
            return HttpResponse('两次密码不一致')
        # 判断原密码是否正确
        is_right = request.user.check_password(old_pwd)
        if not is_right:
            return HttpResponse('原密码不正确')

        # 修改密码
        request.user.set_password(new_pwd)
        request.user.save()
        return HttpResponse('密码修改成功')

    return render(request, 'setPwdPage.html')
--------------------------------------------

@login_required(login_url='/app01/login/')
def logout_func(request):
    auth.logout(request)
    return HttpResponse('退出登录')

--------------------------------------------
@login_required(login_url='/app01/login/')
def book_add_func(request):
    # 2. 获取页面上用户输入的值
    if request.method == 'POST':
        title = request.POST.get('title')
        price = request.POST.get('price')
        publish_time = request.POST.get('publish_time')
        publish_id = request.POST.get('publish_id')
        author_id_list = request.POST.getlist('author_id_list')
        # 3. 对获取的数据进行写判断
        if len(title) == 0 or len(price) == 0:
            return HttpResponse('书名与价格不能为空')
        # 4. 判断书名是否已存在
        res = models.Book.objects.filter(title=title)
        if res:
            return HttpResponse('书名已存在!')
        # 5. 没有问题后往数据库里面书籍表里添加数据
        book_obj = models.Book.objects.create(title=title,
                                              price=price,
                                              publish_time=publish_time,
                                              publish_id=publish_id, )
        book_obj.authors.add(*author_id_list)
        # 6. 重定向到书籍展示页
        return redirect(reverse('book_list_view'))

    # 1. 分析可得html页面需要全部的出版社数据与全部的作者数据!!
    publish_queryset = models.Publish.objects.all()
    author_queryset = models.Author.objects.all()
    return render(request, 'bookAddPage.html', locals())

---------------------------------------------------
@login_required(login_url='/app01/login/')
def book_edit_func(request, book_pk):
    # 1. 根据传到视图函数的数据主键值查询数据对象
    edit_book_obj = models.Book.objects.filter(pk=book_pk).first()  # first()不要忘了

    # 4. 获取用户编辑后发送的post请求后的数据
    if request.method == 'POST':
        title = request.POST.get('title')
        price = request.POST.get('price')
        publish_time = request.POST.get('publish_time')
        publish_id = request.POST.get('publish_id')
        author_id_list = request.POST.getlist('author_id_list')
        # 对获取的数据进行写判断
        if len(title) == 0 or len(price) == 0:
            return HttpResponse('书名与价格不能为空')
        # 5. 没有问题后往数据库里面书籍表里添加数据
        models.Book.objects.filter(pk=book_pk).update(title=title,
                                                      price=price,
                                                      publish_time=publish_time,
                                                      publish_id=publish_id)
        edit_book_obj.authors.set(author_id_list)
        return redirect(reverse('book_list_view'))

    # 3. 分析可得编辑页面也需要所有的出版社和作者信息!!!直接复制上面视图函数的代码!!
    publish_queryset = models.Publish.objects.all()
    author_queryset = models.Author.objects.all()

    # 2. 传递给html页面,并展示给用户看
    return render(request, 'bookEditPage.html', locals())
-------------------------------------------
@login_required(login_url='/app01/login/')
def book_delete_func(request, book_pk):
    # 1. 先拿到书籍表要删除的书籍对象!!!
    delete_book_obj = models.Book.objects.filter(pk=book_pk).first()
    # 2. 再删除数据对象第3张表里面的与作者的对应关系
    delete_book_obj.authors.clear()
    # 3. 最后再删除该书籍对象!!!
    models.Book.objects.filter(pk=book_pk).delete()
    return redirect('book_list_view')
-------------------------------------------

.
.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="/static1/jQuery3.6.js"></script>
# 注意static1是路由,后面是该静态文件存与static文件夹下的路径!!!

    {% load static %}   # 接口前缀的动态匹配模板语法 此处static是个py文件,与路由无关
    <link rel="stylesheet" href={% static "bootstrap-3.4.1-dist/css/bootstrap.min.css" %}>
    <script src={% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}></script>


    {% block css %}

    {% endblock %}
</head>
<body>
<!--导航条-->
    <nav class="navbar navbar-inverse">
      <div class="container-fluid">
            <!-- Brand and toggle get grouped for better mobile display -->
                <div class="navbar-header">
                  <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                        <span class="sr-only">Toggle navigation</span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                  </button>
                  <a class="navbar-brand" href="#">BMS</a>
                </div>

            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                  <ul class="nav navbar-nav">
                        <li class="active"><a href="#">图书<span class="sr-only">(current)</span></a></li>
                        <li><a href="#">作者</a></li>
                        <li class="dropdown">
                          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">更多 <span class="caret"></span></a>
                          <ul class="dropdown-menu">
                            <li><a href="#">快点行动</a></li>
                            <li><a href="#">等不了了</a></li>
                            <li><a href="#">快点我</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">更多美女</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">快速赚钱法</a></li>
                          </ul>
                        </li>
                  </ul>
                  <form class="navbar-form navbar-left">
                        <div class="form-group">
                          <input type="text" class="form-control" placeholder="书名">
                        </div>
                        <button type="submit" class="btn btn-default">查询</button>
                  </form>

                  <ul class="nav navbar-nav navbar-right">
                      {% if request.user.is_authenticated %}
                            <li><a href="#">{{ request.user.username }}</a></li>
                      {% else %}
                            <li><a href="{% url 'register_func_view' %}">注册</a></li>
                        <li><a href="{% url 'login_func_view' %}">登录</a></li>
                      {% endif %}

                        <li class="dropdown">
                          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">更多操作<span class="caret"></span></a>
                          <ul class="dropdown-menu">
                                <li><a href="{% url 'logout_func_view' %}">账号退出</a></li>
                                <li><a href="{% url 'set_pwd_func_view' %}">修改密码</a></li>
                                <li><a href="#">投诉建议</a></li>
                                <li role="separator" class="divider"></li>
                                <li><a href="#">联系管理员</a></li>
                          </ul>
                        </li>
                  </ul>
            </div><!-- /.navbar-collapse -->
      </div><!-- /.container-fluid -->
    </nav>

<!--左边栏-->
    <div class="container-fluid">
        <div class="row">

            <div class="col-md-2">
                <div class="list-group" >
                      <a href="{% url 'home_view' %}" class="list-group-item active text-center" id="exit1">首页展示</a>
                      <a href="{% url 'book_list_view' %}" class="list-group-item text-center" id="exit2">图书列表</a>
                      <a href="#" class="list-group-item text-center" id="exit3">出版社列表</a>
                      <a href="#" class="list-group-item text-center" id="exit4">作者列表</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                </div>
            </div>

    <!--右边栏-->
            <div class="col-md-10">
                <!--面板-->
                    <div class="panel panel-primary">
                          <div class="panel-heading">
                            <h3 class="panel-title"><span class="glyphicon glyphicon-th-list" id="span1"></span>图书管理系统</h3>
                          </div>

                          <div class="panel-body">

                              {% block content %}
                                        <!--页头-->
                                    <div class="page-header">
                                      <h1>图书管理系统 <small id="small1">更多精彩等你来查</small></h1>
                                    </div>

                                   <!--巨幕-->
                                    <div class="jumbotron" id="d1">
                                      <h1>全球最大的网上图书管理系统</h1>
                                      <p id="p1">友情连接</p>
                                      <p><a class="btn btn-primary btn-lg" href="#" role="button">点击精彩</a>

                                          <button type="button" class="btn btn-primary btn-lg" aria-label="Left Align">
                                              <span class="glyphicon glyphicon-lock " aria-hidden="true"></span>
                                          </button>

                                      </p>
                                    </div>

                                  <!--"右下图片区"-->
                                    <div class="row">
                                            <div class="col-xs-6 col-md-3">
                                            <a href="#" class="thumbnail">
                                                <sapn class="glyphicon glyphicon-heart"></sapn> <sapn class="glyphicon glyphicon-heart"></sapn>  <sapn class="glyphicon glyphicon-heart"></sapn>
                                              <img src="xxx" alt="...">

                                            </a>
                                          </div>
                                            <div class="col-xs-6 col-md-3">
                                                <a href="#" class="thumbnail">
                                                    <sapn class="glyphicon glyphicon-heart"></sapn> <sapn class="glyphicon glyphicon-heart"></sapn>  <sapn class="glyphicon glyphicon-heart"></sapn>
                                                  <img src="xxx" alt="...">
                                                </a>
                                              </div>
                                            <div class="col-xs-6 col-md-3">
                                                <a href="#" class="thumbnail">
                                                    <sapn class="glyphicon glyphicon-heart"></sapn> <sapn class="glyphicon glyphicon-heart"></sapn>  <sapn class="glyphicon glyphicon-heart"></sapn>
                                                  <img src="xxx" alt="...">
                                                </a>
                                              </div>
                                            <div class="col-xs-6 col-md-3">
                                                <a href="#" class="thumbnail">
                                                    <sapn class="glyphicon glyphicon-heart"></sapn> <sapn class="glyphicon glyphicon-heart"></sapn>  <sapn class="glyphicon glyphicon-heart"></sapn>
                                                  <img src="xxx" alt="...">
                                                </a>
                                              </div>
                                    </div>  <!--"内部的row"-->
                              {% endblock %}

                          </div>   <!--"panel-body"-->
                    </div>  <!--"panel panel-primary"-->
            </div>   <!--"col-md-10"-->

        </div> <!--"row"-->

    </div> <!--"container-fluid"-->


{% block js %}

{% endblock %}
</body>
</html>

.
.

{% extends 'homePage.html' %}

{% block css %}

{% endblock %}


<!--内容区-->
{% block content %}
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <form action="" method="post">
                {% csrf_token %}
                <p>用户名:
                    <input type="text" name="username" class="form-control">
                </p>
                <p>密码:
                    <input type="text" name="password" class="form-control">
                </p>

                <p>确认密码:
                    <input type="text" name="confirm_password" class="form-control">
                </p>

                <input type="submit" value="注册" class="btn btn-primary btn-block">
            </form>
        </div>
    </div>
{% endblock %}


{% block js %}

{% endblock %}

.
.

{% extends 'homePage.html' %}
{% block css %}

{% endblock %}

<!--内容区-->
{% block content %}
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <form action="" method="post">
                {% csrf_token %}
                <p>用户名:
                    <input type="text" name="username" class="form-control">
                </p>
                <p>密码:
                    <input type="text" name="password" class="form-control">
                </p>
                <input type="submit" value="登录" class="btn btn-primary btn-block">
            </form>
        </div>
    </div>
{% endblock %}



改密码

{% extends 'homePage.html'%}


{% block css %}

{% endblock %}


<!--内容区-->
{% block content %}
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <form action="" method="post">
                {% csrf_token %}
                <p>原密码:
                    <input type="text" name="old_pwd" class="form-control">
                </p>
                <p>新密码:
                    <input type="text" name="new_pwd" class="form-control">
                </p>

                <p>确认密码:
                    <input type="text" name="confirm_password" class="form-control">
                </p>

                <input type="submit" value="确认修改密码" class="btn btn-primary btn-block">
            </form>
        </div>
    </div>
{% endblock %}


{% block js %}

{% endblock %}

.
.
booklistpage

{% extends 'homePage.html' %}

{% block css %}

{% endblock %}

<!--内容区-->
{% block content %}
    <h2 class="text-center">图书展示页</h2>
    <a href="{% url 'book_add_view' %}" class="btn btn-warning">图书添加</a>
    <table class="table table-striped table-hover">
        <thead>
            <tr>
                <th>编号</th>
                <th>书名</th>
                <th>价格</th>
                <th>出版日期</th>
                <th>出版社</th>
                <th>作者</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            {% for book_obj in part_book_queryset %} <!--QuerySet[书对象,书对象]-->
                <tr>
                    <td>{{ forloop.counter }}</td> <!--可以展示主键值也可以展示从一开始的有序数列-->
                    <td>{{ book_obj.title }}</td>
                    <td>{{ book_obj.price }}</td>
                    <td>{{ book_obj.publish_time|date:'Y-m-d' }}</td>
                    <td class="btn btn-info">{{ book_obj.publish.name }}</td>
                    <td ><!--注意多对多的这张表是一个虚拟表,通过书对象点虚拟外键字段authors只会跳到Author作者表,不会往虚拟表上添加!!-->
                        {% for author_obj in book_obj.authors.all %}  <!--QuerySet[作者对象,作者对象]-->
                            <span style="margin-right: 5px" class="btn btn-success">{{ author_obj.name }}</span>
{#                            {% if forloop.last %}#}
{#                                {{ author_obj.name }}#}
{#                            {% else %}#}
{#                                {{ author_obj.name }} /#}
{#                            {% endif %}   <!--for循环出的是最后一个不加分隔符,其他的末尾加个分隔符!!-->#}
                        {% endfor %}
                    </td>
                    <td>
                        <!--先拿到别名'book_edit_view'反向解析出路由book_edit/ 再加上for循环出的每一个书籍对象的主键值,一起拼出新的路由-->
                        <!--a标签的作用是跳转到这个新的路由网址上去,跳转到新的路由网址上去后,首先还是要先到路由层匹配视图函数-->
                        <!--当匹配上后,将request与book_pk=从网址上匹配到的动态的路由结果,再传递给视图函数!!-->
                        <a href="{% url 'book_edit_view' book_obj.pk %} " class="btn btn-primary btn-xs">编辑</a>

                        <a href=" " class="btn btn-danger btn-xs delBtn">删除</a>
                    </td>
                </tr>
            {% endfor %}

        </tbody>
    </table>

    <!--分页器!!-->
    <nav aria-label="Page navigation" class="text-center">
              <ul class="pagination">   <!--这个是属性是让列表标签浮动起来,让原来竖排变成横排!!-->
                <!--往左的小按钮-->
                <li>
                  <a href="#" aria-label="Previous">
                    <span aria-hidden="true">&laquo;</span>
                  </a>
                </li>

                <li><a href="#">1</a></li>  <!--原来手动写的分页标签全部不要-->
                <li><a href="#">2</a></li>  <!--原来手动写的分页标签全部不要-->
                <li><a href="#">3</a></li>  <!--原来手动写的分页标签全部不要-->
                  {{ html_str|safe }}       <!--全部让后端自动生成好了传过来-->

                <!--往右的小按钮-->
                <li>
                  <a href="#" aria-label="Next">
                    <span aria-hidden="true">&raquo;</span>
                  </a>
                </li>
              </ul>
    </nav>
{% endblock %}

<!--js区-->
<!--给删除按钮添加一个删除点击确认事件!!-->
{% block js %}
    <script>
        $('.delBtn').click(function () {
            let res = confirm('你确定要删除吗?')
            if (!res){
                return false
            }
        })
    </script>
{% endblock %}



bookaddpage

{% extends 'homePage.html' %}
{% block css %}

{% endblock %}

<!--内容区-->
{% block content %}
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <h2 class="text-center">图书添加页</h2>
            <form action="" method="post">
                {% csrf_token %}
                <p> 书名:
                    <input type="text" name="title" class="form-control">
                </p>
                <p> 价格:
                    <input type="text" name="price" class="form-control">
                </p>
                <p> 出版日期:
                    <input type="date" name="publish_time" class="form-control">
                </p>

                <p>出版社名称:
                    <!--展示系统中已有的出版社信息供选择-->
                    <select name="publish_id" id="" class="form-control">
                        {% for publish_obj in publish_queryset %}
                            <option value="{{ publish_obj.id }}">{{ publish_obj.name }}</option>
                        {% endfor %}
                    </select>
                </p>

                <p>作者名称list:
                    <select name="author_id_list" id="" multiple class="form-control">
                        {% for author_obj in author_queryset %}
                            <option value="{{ author_obj.id }}">{{ author_obj.name }}</option>
                        {% endfor %}
                    </select>
                </p>
                <input type="submit" value="书籍的添加" class="btn btn-block btn-success">
            </form>
        </div>
    </div>
{% endblock %}


{% block js %}

{% endblock %}

.
.
bookeditpage

<!--书籍编辑页-->

{% extends 'homePage.html' %}     <!--继承母板-->

<!--css区-->
{% block css %}

{% endblock %}


<!--内容区-->
{% block content %}
        <div class="row">
        <div class="col-md-6">
            <h2 class="text-center">图书编辑页</h2>
                <form action="" method="post" >
                {% csrf_token %}

                    <p> 书名:
                        <input type="text" name="title" class="form-control" value="{{ edit_book_obj.title }}">
                    </p>
                    <p> 价格:
                        <input type="text" name="price" class="form-control" value="{{ edit_book_obj.price }}">
                    </p>
                    <p> 出版日期:
                        <input type="date" name="publish_time" class="form-control" value="{{ edit_book_obj.publish_time|date:'Y-m-d' }}">
                    </p>

                    <p> 出版社名称:
                        <!--展示系统中已有的出版社信息供选中-->
                        <select name="publish_id" id="" class="form-control">
                            {% for publish_obj in publish_queryset %}  <!--queryset [数据对象,数据对象]-->
                                <!--根据待编辑的书籍对象查询对应的出版社对象,与系统所有的出版社对象比对,如果相同则添加默认选中的属性selected-->
                                {% if edit_book_obj.publish == publish_obj %}
                                    <option value="{{ publish_obj.id }}"selected>{{ publish_obj.name }}</option>
                                {% else %}
                                    <option value="{{ publish_obj.id }}">{{ publish_obj.name }}</option>
                                {% endif %}
                            {% endfor %}
                        </select>
                    </p>

                    <p> 作者名称list:
                        <select name="author_id_list" id="" multiple class="form-control">   <!--一个图书可以有多个作者,加个multiple可以多选-->
                            {% for author_obj in author_queryset %}  <!--queryset [数据对象,数据对象]-->
                                <!--成员运算判断判断,循环的作者对象是否在待编辑的书籍作者对象列表中-->
                                {% if author_obj in edit_book_obj.authors.all %}
                                    <option value="{{ author_obj.id }}"selected>{{ author_obj.name }}</option>
                                {% else %}
                                    <option value="{{ author_obj.id }}">{{ author_obj.name }}</option>
                                {% endif %}
                            {% endfor %}
                        </select>
                    </p>
                    <input type="submit" value="书籍的编辑" class="btn btn-block btn-danger">
                </form>
        </div> <!--"col-md-6"-->

        <div class="col-md-6">
            <img style="max-width:100%" src="https://file.moyublog.com/d/file/2021-02-14/c7e482715ac8cd045c3964b147231ee8.jpg" alt="..." class="img-rounded">
        </div>


    </div> <!--"row"-->

{% endblock %}


<!--js区-->
{% block js %}

{% endblock %}

.
.
.

补充:使用自定义分页器的情况:

@login_required(login_url='/app01/login/')
def book_list_func(request):
    all_book_queryset = models.Book.objects.all()
    # 用自定义分页器
    from app01.others.mypage import Pagination   # 导写好的分页器类的py文件!
    current_page = request.GET.get('page', 1)  # 按键正常拿值,拿不到就按1拿
    all_count = all_book_queryset.count()
    # 只需要传两个参数就行,每页显示的数据条数与与最多显示的页码格式,类里面已经提前写好了,要改去类里面改
    page_obj = Pagination(current_page=current_page, all_count=all_count)
    page_queryset = all_book_queryset[page_obj.start:page_obj.end]
    return render(request, 'bookListPage111.html', locals())
-----------------------------------
html代码:
{% extends 'homePage.html' %}

{% block css %}

{% endblock %}

<!--内容区-->
{% block content %}
    <h2 class="text-center">图书展示页</h2>
    <a href="{% url 'book_add_view' %}" class="btn btn-warning">图书添加</a>
    <table class="table table-striped table-hover">
        <thead>
            <tr>
                <th>编号</th>
                <th>书名</th>
                <th>价格</th>
                <th>出版日期</th>
                <th>出版社</th>
                <th>作者</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            {% for book_obj in page_queryset %} <!--QuerySet[书对象,书对象]-->
                <tr>
                    <td>{{ forloop.counter }}</td> <!--可以展示主键值也可以展示从一开始的有序数列-->
                    <td>{{ book_obj.title }}</td>
                    <td>{{ book_obj.price }}</td>
                    <td>{{ book_obj.publish_time|date:'Y-m-d' }}</td>
                    <td class="btn btn-info">{{ book_obj.publish.name }}</td>
                    <td ><!--注意多对多的这张表是一个虚拟表,通过书对象点虚拟外键字段authors只会跳到Author作者表,不会往虚拟表上添加!!-->
                        {% for author_obj in book_obj.authors.all %}  <!--QuerySet[作者对象,作者对象]-->
                            <span style="margin-right: 5px" class="btn btn-success">{{ author_obj.name }}</span>
{#                            {% if forloop.last %}#}
{#                                {{ author_obj.name }}#}
{#                            {% else %}#}
{#                                {{ author_obj.name }} /#}
{#                            {% endif %}   <!--for循环出的是最后一个不加分隔符,其他的末尾加个分隔符!!-->#}
                        {% endfor %}
                    </td>
                    <td>
                        <!--先拿到别名'book_edit_view'反向解析出路由book_edit/ 再加上for循环出的每一个书籍对象的主键值,一起拼出新的路由-->
                        <!--a标签的作用是跳转到这个新的路由网址上去,跳转到新的路由网址上去后,首先还是要先到路由层匹配视图函数-->
                        <!--当匹配上后,将request与book_pk=从网址上匹配到的动态的路由结果,再传递给视图函数!!-->
                        <a href="{% url 'book_edit_view' book_obj.pk %} " class="btn btn-primary btn-xs">编辑</a>

                        <a href="{% url 'book_delete_view' book_obj.pk %} " class="btn btn-danger btn-xs delBtn">删除</a>
                    </td>
                </tr>
            {% endfor %}

        </tbody>
    </table>

    <!--分页器!!-->
    <!--已经把所有分页的代码,全部封装好了,就一行代码完事-->
    {{ page_obj.page_html|safe }}

{% endblock %}

<!--js区-->
<!--给删除按钮添加一个删除点击确认事件!!-->
{% block js %}
    <script>
        $('.delBtn').click(function () {
            let res = confirm('你确定要删除吗?')
            if (!res){
                return false
            }
        })
    </script>
{% endblock %}

.
.

别人写好的分页器类代码(mypage.py)

# 把整个分页器代码全部封装到后端来写

class Pagination(object):
    def __init__(self, current_page, all_count, per_page_num=3, pager_count=11):
        """
        封装分页相关数据
        :param current_page: 当前页
        :param all_count:    数据库中的数据总条数
        :param per_page_num: 每页显示的数据条数
        :param pager_count:  最多显示的页码个数(或者说分页器标签的个数)
        """
        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1

        if current_page < 1:
            current_page = 1

        self.current_page = current_page

        self.all_count = all_count
        self.per_page_num = per_page_num

        # 总页码
        all_pager, tmp = divmod(all_count, per_page_num)
        if tmp:
            all_pager += 1
        self.all_pager = all_pager

        self.pager_count = pager_count
        self.pager_count_half = int((pager_count - 1) / 2)

    @property
    def start(self):
        return (self.current_page - 1) * self.per_page_num

    @property
    def end(self):
        return self.current_page * self.per_page_num

    def page_html(self):
        # 如果总页码 < 11个:
        if self.all_pager <= self.pager_count:
            pager_start = 1
            pager_end = self.all_pager + 1
        # 总页码  > 11
        else:
            # 当前页如果<=页面上最多显示11/2个页码
            if self.current_page <= self.pager_count_half:
                pager_start = 1
                pager_end = self.pager_count + 1

            # 当前页大于5
            else:
                # 页码翻到最后
                if (self.current_page + self.pager_count_half) > self.all_pager:
                    pager_end = self.all_pager + 1
                    pager_start = self.all_pager - self.pager_count + 1
                else:
                    pager_start = self.current_page - self.pager_count_half
                    pager_end = self.current_page + self.pager_count_half + 1

        page_html_list = []
        # 添加前面的nav和ul标签
        page_html_list.append('''
                    <nav aria-label='Page navigation>'
                    <ul class='pagination'>
                ''')
        first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
        page_html_list.append(first_page)

        if self.current_page <= 1:
            prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
        else:
            prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)

        page_html_list.append(prev_page)

        for i in range(pager_start, pager_end):
            if i == self.current_page:
                temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
            else:
                temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
            page_html_list.append(temp)

        if self.current_page >= self.all_pager:
            next_page = '<li class="disabled"><a href="#">下一页</a></li>'
        else:
            next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
        page_html_list.append(next_page)

        last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
        page_html_list.append(last_page)
        # 尾部添加标签
        page_html_list.append('''
                                           </nav>
                                           </ul>
                                       ''')
        return ''.join(page_html_list)

.
.

分页器标签在页面渲染的页码个数(或者说分页器标签的个数) 控制思路

当不用别人写好的类,自己写分页器代码的时候,发现鬼玩意真不好写
上面我自己写的分页器标签有点问题:
---------------------------------
  html_str = ''
    xxx = current_page
    yyy = current_page
    if xxx < 6:
        xxx = 6
    if yyy > all_page_num - 5:
        yyy = all_page_num - 5

    # 注意这个地方玩的很骚,用变量名xxx指代current_page来控制分页的标签的个数与标签显示的样式,这地方分页标签的个数展示还有点问题(这个地方逻辑有点烦)
    for i in range(xxx - 5, yyy + 6):
        # 下面用还用current_page变量名来控制用户实际点的是哪一页,就将该分页显示选中
        if current_page == i:
            html_str += '<li class="active"> <a href="?page=%s">%s</a></li>' % (i, i)
        else:
            html_str += '<li> <a href="?page=%s">%s</a></li>' % (i, i)
    # 每次for循环产生一个新的分页标签的代码的字符串,和原来的字符串进行一个拼接,
    # 最后结束,所有的标签代码的字符串都拼接在一起,被html_str变量接收,传给html,利用过滤器 |safe 解析出代码
---------------------------------------
问题在哪儿了,虽然当前的方法可以控制分页器标签不在显示负数 ,以及不再显示的页码数大于总页码,但是还是有问题,比如我选择页面数为2的时候,显示的确实1-7分页标签,为什么会这样?
因为当前页为2的时候,yyy并没有大于all_page_num - 5,所以不会将yyy变成all_page_num - 5
yyy还是2,所以 range(1,8) 所以最后渲染出7个标签出来

image

分析思路如下:
current_page:  当前页
all_count:     数据库中的数据总条数
per_page_num:  每页显示的数据条数
pager_count:   最多显示的页码个数(或者说分页器标签的个数)  假设我们定为11
---------------------------
range(pager_start,pager_end)
总共4种情况:对应的range括号里面的初始与结束的页码数都不一样!!!
-----------------
第一种情况:总页码小于我们定的最多显示的分页器标签个数时,很显然要按实际我们的总页码来,将所有页码都显示出来即可所以:
pager_start = 1
pager_end = all_pager(总页码) + 1
------------------------------------------
第二种情况:总页码大于我们定的最多显示的分页器标签个数(11)时,且当前我们选择跳转的页码小于最多显示的页码的个数的一半时,比如12345时:
此时开始页肯定还是从1开始,但结束页就应该是11(最多显示的分页器标签的个数),也就是说当选择跳转的页面小于最多显示的页码的个数的一半时,按理就应该让页面显示的标签就是1-1111个分页标签
pager_start = 1
pager_end =pager_count + 1
-------------------------------------------
第三种情况:总页码大于我们定的最多显示的分页器标签个数(11)时,当前选择跳转的页大于5,且总页码数大于(当前页+5)时,比如总页码是100页,当前页是8页,这种情况下,按理就应该让页面显示的标签就是3-1311个分页标签,当前页在中间
pager_start = current_page(当前页) - pager_count_half(11/2最多显示页码个数除2就是5)
pager_start = 当前页 - 5
pager_end = 当前页 + pager_count_half(就5)+ 1  = 当前页 + 6
---------------------------------------------
第四种情况:总页码大于我们定的最多显示的分页器标签个数(11)时,当前选择跳转的页大于5,且总页码数小于(当前页+5)时,比如:当前页是9页,总页码是13页,这种情况下,按理就应该让页面显示的标签就是3-1311个分页标签才对
pager_start = all_pager(总页码)- 最多允许显示的分页器标签个数(11) + 1
pager_end = all_pager(总页码) + 1
---------------------------------------------
那也就是说上面的 代码要这样改:
html_str = ''
    #
    pager_count_half = int((pager_count - 1) / 2)
    if all_page_num <= pager_count:  # 如果总页码 < 11个:
        pager_start = 1
        pager_end = all_page_num + 1
    # 总页码 > 11 页
    else:
        # 且当前页如果<=页面上最多显示个页码(11-1)/2时,就是当前页小于5页
        if current_page <= pager_count_half:
            pager_start = 1
            pager_end = pager_count + 1

        # 且当前页大于5页情况:
        else:
            # 当前页加5页大于总页数了,分页标签直接从最后页往前显示11个分页标签就行了(页码翻到最后)
            if (current_page + pager_count_half) > all_page_num:
                pager_end = all_page_num + 1
                pager_start = all_page_num - pager_count + 1
            # 当前页加5页小于总页数了,这就是最正常的情况(总页码>11页,且当前页大于5,且当前页加5小于总页数),用当前页来控制起始
            else:
                pager_start = current_page - pager_count_half       # 当前页-5
                pager_end = current_page + pager_count_half + 1     # 当前页+6

    for i in range(pager_start, pager_end):
        # 下面用还用current_page变量名来控制用户实际点的是哪一页,就将该分页显示选中
        if current_page == i:
            html_str += '<li class="active"> <a href="?page=%s">%s</a></li>' % (i, i)
        else:
            html_str += '<li> <a href="?page=%s">%s</a></li>' % (i, i)
---------------------------------------------
这样改完分页器 还有一个地方没改好了,就是每页器左右两边的前进与后退的按钮,目前没有作用,具体怎么改,参考别人写好的分页器类怎么写的,再改!!!视图函数再加代码
    if current_page <= 1:
        html_prev_str = '<li class="disabled"><a href="#">上一页</a></li>'
    else:
        html_prev_str = '<li><a href="?page=%s">上一页</a></li>' % (current_page - 1,)

    if current_page >= all_page_num:
        html_next_str = '<li class="disabled"><a href="#">下一页</a></li>'
    else:
        html_next_str = '<li><a href="?page=%s">下一页</a></li>' % (current_page + 1,)

class="disabled  让该标签显示,当不再具有功能,禁用了。非常符合当点到第一页的时候,给向左的按钮禁掉不让用
-------
html页面原来的往左与往右的小按钮代码全部不需要了,直接就一行代码
             <!--往左的小按钮-->
{#              <li>#}
{#                  <a href="#" aria-label="Previous">#}
{#                    <span aria-hidden="true">&laquo;</span>#}
{#                  </a>#}
{#                </li>#}
                  {{ html_prev_str|safe }}            # 往左按钮

                  {{ html_str|safe }}                 # 分页标签的按钮

                  {{ html_next_str|safe }}            # 往右按钮
--------------------------------------------
最后如果还想加个首页与尾页的按钮,还是一样抄别人类里面怎么写的。
视图函数再加代码:
first_page_str = '<li><a href="?page=%s">首页</a></li>' % (1)
last_page_str = '<li><a href="?page=%s">尾页</a></li>' % (all_page_num,)

html页面再加代码:
                 {{ first_page_str|safe }}
                  {{ html_prev_str|safe }}

                    {{ html_str|safe }}

                  {{ html_next_str|safe }}
                  {{ last_page_str|safe }}
---------------------------------------------
一个鸟分页器在分页器标签的显示个数这绕的一笔!!! 不如直接用别人写好的分页器类!!!!
创个others文件夹,穿个py文件,把别人写好的分页器类代码复制粘贴进去,保存一下
哪个视图函数需要用分页器,再该视图函数内部导入该分页器类,先拿到当前页与总页数,然后分页器类名加括号生成对象的同时,传给分页器对象。然后分页器对象点start与end拿到值对总的equeryset对象做切片操作!!! 对象点的start方法其实就是我们自己手写的方法
start_num = (current_page - 1) * per_page_num  # 起始展示对象的位置索引
---------
def book_list_func(request):
    all_book_queryset = models.Book.objects.all()
    # 用自定义分页器
    from app01.others.mypage import Pagination   # 导写好的分页器类的py文件!
    current_page = request.GET.get('page', 1)  # 按键正常拿值,拿不到就按1拿
    all_count = all_book_queryset.count()
    # 只需要传两个参数就行,每页显示的数据条数与与最多显示的页码格式,类里面已经提前写好了,要改去类里面改
    page_obj = Pagination(current_page=current_page, all_count=all_count)
    page_queryset = all_book_queryset[page_obj.start:page_obj.end]
    return render(request, 'bookListPage111.html', locals())

最终用自己的分页器也能达到效果
image

posted @   tengyifan  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示