Django开发从入门到实践学习笔记

操作系统版本:Windows 10
python版本:Python 3.9.12
pip版本:pip 21.2.4
Django版本:Django 3.0.6

软件安装

python

官网下载python3

在这里插入图片描述
注意勾选Add Python 3.9 to PATH

或应用商店中下载python3
在这里插入图片描述

查看安装情况

python -V
PS C:\Users\Thinkpad> python -V
Python 3.9.12

Django

安装Django

pip install django==3.0.6

查看安装情况

pip list
PS C:\Users\Thinkpad> pip list
Package    Version
---------- -------
Django     3.0.6

vscode

在这里插入图片描述

书籍管理系统

项目定位

实现目标:藏书管理系统
项目定位:社团内部使用、用户量较少、使用频次相对低、功能单一且确定

功能需求

用户注册、用户分级、用户登录、书籍信息的添加、书籍信息的修改、书籍信息的删除、书籍信息的分类展示、书籍信息的查询

产品设计

URL方法静态页面用途顺序
index/views.indexindex.html用户进入系统时的欢迎页面1
sign_up/views.sign_upsign_up.html用户注册页面2
login/views.loginlogin.html用户登录页面3
logout/views.logout/用户退出页面4
change_password/views.change_passwordchange_password.html修改口令页面5
add_book/views.add_bookadd_book.html书籍信息的添加页面6
book_list/views.book_listbook_list.html书籍列表页面7

数据模型

书籍

字段类型名称默认值长度
nameCharField书籍名称非空128bit
authorCharField作者可空64bit
priceFloatField书籍定价0.0/
publish_dateDateTimeField出版日期可空/
cateoryCharField书籍分类未分类32bit
create_datetimeDateTimeField书籍添加时间auto_now_add/

用户

使用Django用户表auth_user

在这里插入图片描述

开始实践

创建项目和应用

创建BookManagement项目

cd C:\Code
django-admin startproject BookManagement

创建management应用

cd BookManagement
django-admin startapp management

打开vscode–>文件(File)–>打开文件夹(Open Folder)–>C:\Code\BookManagement–>确定–>终端(Terminal)–>新建终端(New Terminal)

在这里插入图片描述
启动Django开发服务器

python manage.py runserver
PS C:\Code\BookManagement> python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 17 unapplied migration(s). Your project may not work properly until you apply the 
migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
April 27, 2022 - 19:44:29
Django version 3.0.6, using settings 'BookManagement.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

在这里插入图片描述

在settings.py中INSTALLED_APPS位置添加新建应用management

C:\Code\BookManagement\BookManagement\settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'management',  # 添加新建应用management
]

用户进入系统时的欢迎页面

编辑BookManagement项目urls.py,包含management应用urls.py

C:\Code\BookManagement\BookManagement\urls.py
"""BookManagement URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('management.urls')),  # 将management应用的URL设置包含到项目的URL设置中
]

创建并编辑management应用urls.py

C:\Code\BookManagement\management\urls.py
from django.urls import URLPattern, path
from management import views

urlpatterns = [
    path('', views.index, name='homepage'),  # 用户进入系统时的欢迎页面 
    path('index/', views.index, name='homepage'),  # 用户进入系统时的欢迎页面 
]
C:\Code\BookManagement\management\views.py
def index(request):
    return render(request,"management/index.html")

在BookManagement项目下创建templates文件夹,再到templates文件夹中为management应用创建management子目录,即BookManagement-templates-management

设置settings.py中TEMPLATES-DIRS,添加templates

C:\Code\BookManagement\BookManagement\settings.py
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],  # 添加templates
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

在BookManagement-templates-management下创建index.html作为主页

BookManagement-templates-management-index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主页</title>
    主页
</head>
<body>
</body>
</html>
http://127.0.0.1:8000

在这里插入图片描述
需要使用Bootstrap3快速编写前端样式,选择Bootstrap版本,下载Bootstrap3

在这里插入图片描述选择用于生产环境的Bootstrap部署方式
在这里插入图片描述

在C:\Code\BookManagement\management\下创建static目录,放置Bootstrap3静态文件css、fonts、js等

C:\Code\BookManagement\templates\management\index.html

在这里插入图片描述
将index.html根据结构拆分navbar.html、index.html

C:\Code\BookManagement\templates\management\navbar.html
{% load static %}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>{% block title%}{% endblock %}</title>
    <link rel="stylesheet" type="text/css" href="{% static 'css/bootstrap.min.css' %}">
    <link rel="stylesheet" type="text/css" href="{% static 'css/base.css' %}">
    <script type="text/javascript" src="{% static 'js/jquery.min.js' %}"></script>
    <script type="text/javascript" src="{% static 'js/bootstrap.min.js' %}"></script>
</head>

<body>
    <nav class="navbar navbar-inverse navbar-fixed-top" role="navigatioin">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#navbar-collapse-basepage">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a href="" class="navbar-brand">Library</a>
            </div>
            <div class="collapse navbar-collapse" id="navbar-collapse-basepage">
                <ul class="nav navbar-nav">
                    <li id="homepage" class="active">
                        <a href="">主页</a>
                    </li>
                </ul>
                <ul class="nav navbar-nav navbar-right">
                    <li><a href="/sign_up/">注册</a></li>
                    <li><a href="/login/">登录</a></li>
                </ul>
            </div>
    </nav>
{% block content %}
{% endblock %}
</body>

</html>
C:\Code\BookManagement\templates\management\index.html

在这里插入图片描述

用户注册页面

C:\Code\BookManagement\management\urls.py
from django.urls import URLPattern, path
from management import views

urlpatterns = [
    path('', views.index, name='homepage'),
    path('index/', views.index, name='homepage'),
    path('sign_up/', views.sign_up, name='sign_up'),  # 添加用户注册页面
]

在views.py中追加sign_up

C:\Code\BookManagement\management\views.py
def sign_up(request):
    return render(request,"management/sign_up.html")

在BookManagement-templates-management中新建sign_up.html

C:\Code\BookManagement\templates\management\sign_up.html
{% extends "management/navbar.html" %}

{% block title %}注册{% endblock %}

{% block content %}
    <div class="container" style="height: 100px;"></div>
    <div class="container">
        <div class="row">
            <div class="col-md-6 col-md-offset-3 col-sm-10 col-sm-offset-1">
                <form method="POST" role="form" class="form-horizontal">
                    {% csrf_token %}
                    <h1 class="form-signin-heading text-center">请注册</h1>
                    <div class="form-group">
                        <label for="id_username" class="col-md-3 control-label">用户名:</label>
                        <div class="col-md-9">
                            <input type="text" class="form-control" id="id_username" required name="username" autofocus>
                            <span class="help-block">用于登录,可以包括大小写字母和下划线。</span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="id_password" class="col-md-3 control-label">口令:</label>
                        <div class="col-md-9">
                            <input type="password" class="form-control" id="id_password" required name="password">
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="id_repassword" class="col-md-3 control-label">重复口令:</label>
                        <div class="col-md-9">
                            <input type="password" class="form-control" id="id_repassword" required name="repassword">
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="id_email" class="col-md-3 control-label">电子邮件:</label>
                        <div class="col-md-9">
                            <input type="text" class="form-control" id="id_email" required name="email">
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="col-md-9 col-md-offset-3">
                            <button class="btn btn btn-primary btn-block" type="submit" id="id_submit">注册</button>
                        </div>
                    </div>
                </form>
            </div>
        </div>
    </div>
{% endblock %}

在这里插入图片描述
开始实现后端

用户表使用Django自带的数据表

python manage.py makemigrations
python manage.py migrate
python manage.py runserver
PS C:\Code\BookManagement> python manage.py makemigrations
PS C:\Code\BookManagement> python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying sessions.0001_initial... OK

在views.py添加

C:\Code\BookManagement\management\views.py
from django.contrib.auth.models import User
from django.shortcuts import redirect

def sign_up(request):
    if request.method=="POST":
        username=request.POST.get('username','')
        password=request.POST.get('password','')
        repassword=request.POST.get('repassword','')
        email=request.POST.get('email','')
        if password=='' or repassword=='':
            state='empty'
        elif password != repassword:
            state='repeat_error'
        else:
            if User.objects.filter(username=username):
                state='user_exist'
            else:
                new_user=User.objects.create_user(username=username,password=password,email=email)
                new_user.save()
                state='success'
                return redirect("/index/")
    return render(request,"management/sign_up.html")

在这里插入图片描述
能够添加用户了,添加成功后会跳转到index,添加未成功则保持当前界面

用户登录页面

C:\Code\BookManagement\management\urls.py
from django.urls import URLPattern, path
from management import views

urlpatterns = [
    path('', views.index, name='homepage'),
    path('index/', views.index, name='homepage'),
    path('sign_up/', views.sign_up, name='sign_up'),
    path('login/', views.login, name='login'),  # 添加用户登录页面
]

在views.py中追加login

C:\Code\BookManagement\management\views.py
def login(request):
    return render(request,"management/login.html")

在BookManagement-templates-management中新建login.html

C:\Code\BookManagement\templates\management\login.html
{% extends "management/navbar.html" %}

{% block title %}登录{% endblock %}

{% block content %}
    <div class="container" style="height: 100px;"></div>
    <div class="container">
        <div class="row">
            <div class="col-md-6 col-md-offset-3 col-sm-10 col-sm-offset-1">
                <form method="POST" role="form" class="form-horizontal">
                    {% csrf_token %}
                    <h1 class="form-signin-heading text-center">请登录</h1>
                    <div class="form-group">
                        <label for="id_username" class="col-md-3 control-label">用户名:</label>
                        <div class="col-md-9">
                            <input type="text" class="form-control" id="id_username" required name="username" autofocus>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="id_password" class="col-md-3 control-label">口令:</label>
                        <div class="col-md-9">
                            <input type="password" class="form-control" id="id_password" required name="password">
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="col-md-9 col-md-offset-3">
                            <button class="btn btn btn-primary btn-block" type="submit" id="id_submit">登录</button>
                        </div>
                    </div>
                </form>
            </div>
        </div>
    </div>
{% endblock %}

在这里插入图片描述

开始实现后端

在views.py添加

C:\Code\BookManagement\management\views.py
from django.contrib.auth.models import User, auth

def login(request):
    if request.method == "POST":
        username = request.POST.get('username', '')
        password = request.POST.get('password', '')
        if username and password:
            user = auth.authenticate(username=username, password=password)
            if user is not None:
                auth.login(request, user)
                return redirect("/index/")
            else:
                state = 'not_exist_or_password_error'
    return render(request, "management/login.html")

能够登录了,添加成功后会跳转到index,添加未成功则保持当前界面

用户退出页面

C:\Code\BookManagement\management\urls.py
from django.urls import URLPattern, path
from management import views

urlpatterns = [
    path('', views.index, name='homepage'),
    path('index/', views.index, name='homepage'),
    path('sign_up/', views.sign_up, name='sign_up'),
    path('logout/', views.logout, name='logout'),  # 添加用户退出页面
]
C:\Code\BookManagement\management\views.py

在BookManagement-management-views.py添加

def logout(request):
    auth.logout(request)
    return redirect("/index/")

退出无单独界面,成功退出后重定向至index

修改口令页面

C:\Code\BookManagement\management\urls.py
from django.urls import URLPattern, path
from management import views

urlpatterns = [
    path('', views.index, name='homepage'),
    path('index/', views.index, name='homepage'),
    path('sign_up/', views.sign_up, name='sign_up'),
    path('login/', views.login, name='login'),
    path('logout/', views.logout, name='logout'),
    path('change_password/', views.change_password, name='change_password'),  # 添加用户修改口令页面
]

在views.py中追加change_password

C:\Code\BookManagement\management\views.py
def change_password(request):
    return render(request,"management/change_password.html")

在BookManagement-templates-management中新建change_password.html

C:\Code\BookManagement\templates\management\change_password.html
{% extends "management/navbar.html" %}

{% block title %}修改口令{% endblock %}

{% block content %}
    <div class="container" style="height: 100px;"></div>
    <div class="container">
        <div class="row">
            <div class="col-md-6 col-md-offset-3 col-sm-10 col-sm-offset-1">
                <form method="POST" role="form" class="form-horizontal">
                    {% csrf_token %}
                    <h1 class="form-signin-heading text-center">修改口令</h1>
                    <div class="form-group">
                        <label for="id_password" class="col-md-3 control-label">原口令:</label>
                        <div class="col-md-9">
                            <input type="password" class="form-control" id="id_password" required name="password">
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="id_newpassword" class="col-md-3 control-label">现口令:</label>
                        <div class="col-md-9">
                            <input type="password" class="form-control" id="id_newpassword" required name="newpassword">
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="id_confirmpassword" class="col-md-3 control-label">确认口令:</label>
                        <div class="col-md-9">
                            <input type="password" class="form-control" id="id_confirmpassword" required name="confirmpassword">
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="col-md-9 col-md-offset-3">
                            <button class="btn btn btn-primary btn-block" type="submit" id="id_submit">确认修改</button>
                        </div>
                    </div>
                </form>
            </div>
        </div>
    </div>
{% endblock %}

在这里插入图片描述
开始实现后端

在views.py添加

C:\Code\BookManagement\management\views.py
def change_password(request):
    if request.user.is_authenticated:
        if request.method == "POST":
            user = request.user
            password = request.POST.get('password', '')
            newpassword = request.POST.get('newpassword', '')
            confirmpassword = request.POST.get('confirmpassword', '')
            if user.check_password(password):
                if not newpassword:
                    state = 'empty'
                elif newpassword != confirmpassword:
                    state = 'repeat_error'
                else:
                    user.set_password(newpassword)
                    user.save()
                    state = 'success'
                    return redirect('/index/')
            else:
                state = 'password_error'
    return render(request, "management/change_password.html")

能够修改口令了,添加成功后会跳转到index,添加未成功则保持当前界面

书籍信息的添加页面

C:\Code\BookManagement\management\urls.py
from django.urls import URLPattern, path
from management import views

urlpatterns = [
    path('', views.index, name='homepage'),
    path('index/', views.index, name='homepage'),
    path('sign_up/', views.sign_up, name='sign_up'),
    path('login/', views.login, name='login'),
    path('logout/', views.logout, name='logout'),
    path('change_password/', views.change_password, name='change_password'),
    path('add_book/', views.add_book, name='add_book'),  # 添加书籍信息添加页面
]

在BookManagement-management-views.py中追加add_book

C:\Code\BookManagement\management\views.py
def add_book(request):
    return render(request,"management/add_book.html")

在BookManagement-templates-management中新建add_book.html

C:\Code\BookManagement\templates\management\add_book.html

在这里插入图片描述
开始实现后端

创建数据表Book

C:\Code\BookManagement\management\models.py
from django.db import models

# Create your models here.
class Book(models.Model):
    name = models.CharField(max_length=128, verbose_name='书籍名称')
    author = models.CharField(max_length=64, blank=True, verbose_name='作者')
    price = models.FloatField(default=0.0, verbose_name='定价')
    publish_date = models.DateField(null=True, blank=True, verbose_name='出版日期')
    cateory = models.CharField(
        max_length=32, default='未分类', verbose_name='添加日期'
    )
    create_datetime = models.DateTimeField(
        auto_now_add=True, verbose_name='添加日期'
    )  # auto_now_add参数自动填充当前时间

    def __str__(self):  # 定义__str__方法后,在将模型对象作为参数传递给str()函数时会调用该方法返回相应的字符串
        return self.name
python manage.py makemigrations  # 更新数据表更改情况
python manage.py migrate  # 更新数据表
python manage.py runserver  # 启动
PS C:\Code\BookManagement> python manage.py makemigrations
Migrations for 'management':
  management\migrations\0001_initial.py
    - Create model Book
PS C:\Code\BookManagement> python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, management, sessions
Running migrations:
  Applying management.0001_initial... OK

在views.py添加

C:\Code\BookManagement\management\views.py
from management import models

def add_book(request):
    if request.user.is_authenticated:
        if request.method == "POST":
            new_book = models.Book (
                name = request.POST.get('name', ''),
                author = request.POST.get('author', ''),
                price = request.POST.get('price', ''),
                publish_date = request.POST.get('publish_date', ''),
                cateory = request.POST.get('cateory', ''),
                create_datetime = request.POST.get('create_datetime', ''),
            )
            new_book.save()
            state='success'
            return redirect('/book_list/')
    return render(request,"management/add_book.html")

在这里插入图片描述

能够添加书籍信息了,添加成功后会跳转到还未编写的book_list,添加未成功则保持当前界面

书籍列表页面

C:\Code\BookManagement\management\urls.py
from django.urls import URLPattern, path
from management import views

urlpatterns = [
    path('', views.index, name='homepage'),
    path('index/', views.index, name='homepage'),
    path('sign_up/', views.sign_up, name='sign_up'),
    path('login/', views.login, name='login'),
    path('logout/', views.logout, name='logout'),
    path('change_password/', views.change_password, name='change_password'),
    path('add_book/', views.add_book, name='add_book'),
    path('book_list/', views.book_list, name='book_list'),  # 添加书籍列表页面
]

在views.py中追加book_list

C:\Code\BookManagement\management\views.py
def book_list(request):
    return render(request,"management/book_list.html")

在BookManagement-templates-management中新建book_list.html

C:\Code\BookManagement\templates\management\book_list.html
{% extends "management/navbar.html" %}

{% block title %}登录{% endblock %}

{% block content %}
    <div class="container" style="height: 100px;"></div>
    <div class="container">
        <div class="row">
            <div class="col-md-10 col-md-offset-1">
               <div class="list-group">
                     <a href="/book_list/" class="list-group-item" id="id_category_all" style="text-align:center">全部图书</a>
                 </div>
            </div>
            <div class ="col-md-10 col-md-offset-1">
                <table class="table table-hover">
                    <thead>
                        <tr>
                            <th>#</th>
                            <th>书名</th>
                            <th>作者</th>
                            <th>出版日期</th>
                            <th>定价</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for book in book_list %}
                            <tr>
                                <th>{{forloop.counter}}</th>
                                <th><a href="#">{{book.name}}</a></th>
                                <th>{{book.author}}</th>
                                <th>{{book.publish_date}}</th>
                                <th>{{book.price}}</th>
                            </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
{% endblock %}

在这里插入图片描述

开始实现后端

在views.py添加

C:\Code\BookManagement\management\views.py
from management import models

def book_list(request):
    if request.user.is_authenticated:
        if request.method == "GET":
            book_list = models.Book.objects.all().only('name','author','publish_date','price')
            content={
                'book_list':book_list,
            }
            print(content)
            return render(request,"management/book_list.html",content)
    return render(request,"management/book_list.html")

在这里插入图片描述

能够展示书籍列表了

问题:
1.业务功能有限
2.用户体验不够友好
3.安全性不足
4.性能不足

一点优化

展示当前登录用户

当已登录时展示当前登录用户,当未登录时显示注册和登录

C:\Code\BookManagement\templates\management\navbar.html
                <ul class="nav navbar-nav navbar-right">
                    {% if user %}  # 当user不空时显示当前登录用户,点击时修改口令
                        <li><a href="/change_password/">{{user}}</a></li>
                    {% else %}  # 当user为空时显示注册和登录
                        <li><a href="/sign_up/">注册</a></li>
                        <li><a href="/login/">登录</a></li>
                    {% endif %}
                </ul>
C:\Code\BookManagement\management\views.py
def index(request):
    if request.user.is_authenticated:  #当用户已认证时返回user
        user = request.user
        content={
            'user':user,
        }
        return render(request, "management/index.html",content)
    return render(request, "management/index.html")

配置了index页面、book_list页面,但是无任何位置配置book_list页面跳转

C:\Code\BookManagement\templates\management\navbar.html
{% load static %}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>{% block title%}{% endblock %}</title>
    <link rel="stylesheet" type="text/css" href="{% static 'css/bootstrap.min.css' %}">
    <link rel="stylesheet" type="text/css" href="{% static 'css/base.css' %}">
	  <script type="text/javascript" src="{% static 'js/jquery.min.js' %}"></script>
	  <script type="text/javascript" src="{% static 'js/bootstrap.min.js' %}"></script>
</head>

<body>
    <nav class="navbar navbar-inverse navbar-fixed-top" role="navigatioin">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#navbar-collapse-basepage">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a href="/index/" class="navbar-brand">Library</a>  <!-- 添加href跳转index -->
            </div>
            <div class="collapse navbar-collapse" id="navbar-collapse-basepage">
                <ul class="nav navbar-nav">
                    <li id="homepage">
                        <a href="/index/">主页</a>  <!-- 添加href跳转index -->
                    </li>
                    <li id="book_list">  <!-- 添加显示book_list -->
                        <a href="/book_list/">书籍列表</a>  <!-- 添加href跳转book_list -->
                    </li>
                </ul>
                <ul class="nav navbar-nav navbar-right">
                    {% if user %}
                        <li><a href="/change_password/">{{user}}</a></li>
                    {% else %}
                        <li><a href="/sign_up/">注册</a></li>
                        <li><a href="/login/">登录</a></li>
                    {% endif %}
                </ul>
            </div>
    </nav>
{% block content %}
{% endblock %}
</body>

</html>

在这里插入图片描述
书籍列表位置无添加书籍的功能位置

在这里插入图片描述

添加跳转书籍详情页面

添加书籍信息的添加页面的跳转位置

C:\Code\BookManagement\templates\management\book_list.html
{% extends "management/navbar.html" %}

{% block title %}登录{% endblock %}

{% block content %}
    <div class="container" style="height: 100px;"></div>
    <div class="container">
        <div class="row">
            <div class="col-md-10 col-md-offset-1">
                <div class="list-group col-md-10">
                    <a href="/book_list/" class="list-group-item" id="id_category_all" style="text-align:center">全部图书</a>
                </div>
                <div class="list-group col-md-2">
                    <a href="/add_book/" class="list-group-item" id="id_category_all" style="text-align:center">添加书籍</a>  <!-- 添加书籍信息的添加页面的跳转位置 -->
                </div>
            </div>
            <div class ="col-md-10 col-md-offset-1">
                <table class="table table-hover">
                    <thead>
                        <tr>
                            <th>#</th>
                            <th>书名</th>
                            <th>作者</th>
                            <th>出版日期</th>
                            <th>定价</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for book in book_list %}
                            <tr>
                                <th>{{forloop.counter}}</th>
                                <th><a href="#">{{book.name}}</a></th>
                                <th>{{book.author}}</th>
                                <th>{{book.publish_date}}</th>
                                <th>{{book.price}}</th>
                            </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
{% endblock %}

在这里插入图片描述

添加跳转退出界面

添加退出登录页面的跳转

C:\Code\BookManagement\templates\management\navbar.html
{% load static %}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>{% block title%}{% endblock %}</title>
    <link rel="stylesheet" type="text/css" href="{% static 'css/bootstrap.min.css' %}">
    <link rel="stylesheet" type="text/css" href="{% static 'css/base.css' %}">
	  <script type="text/javascript" src="{% static 'js/jquery.min.js' %}"></script>
	  <script type="text/javascript" src="{% static 'js/bootstrap.min.js' %}"></script>
</head>

<body>
    <nav class="navbar navbar-inverse navbar-fixed-top" role="navigatioin">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#navbar-collapse-basepage">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a href="/index/" class="navbar-brand">Library</a>
            </div>
            <div class="collapse navbar-collapse" id="navbar-collapse-basepage">
                <ul class="nav navbar-nav">
                    <li id="homepage">
                        <a href="/index/">主页</a>
                    </li>
                    <li id="book_list">
                        <a href="/book_list/">书籍列表</a>
                    </li>
                </ul>
                <ul class="nav navbar-nav navbar-right">
                    {% if user %}
                        <li><a href="/change_password/">{{user}}</a></li>
                        <li><a href="/logout/">退出</a></li>  <!-- 添加退出登录页面的跳转 -->
                    {% else %}
                        <li><a href="/sign_up/">注册</a></li>
                        <li><a href="/login/">登录</a></li>
                    {% endif %}
                </ul>
            </div>
    </nav>
{% block content %}
{% endblock %}
</body>

</html>

在这里插入图片描述

添加图书的位置未进行前端校验和后端校验

在这里插入图片描述

添加前端校验

进行前端校验

C:\Code\BookManagement\templates\management\add_book.html

在这里插入图片描述
在这里插入图片描述

添加后端校验

C:\Code\BookManagement\management\views.py
class cleandata():
    def TypeNum(data):
        try:
            return int(data)
        except:
            return int(0)
    
    def TypeFloat(data):
        try:
            return float(data)
        except:
            return float(0.00)
    
    def TypeEmail(data):
        try:
            return email(data)
        except:
            return email("@163.com")
    
    def TypeUsername(data):
        try:
            return tostring(data).replace(["'","<",">","#"],"")
        except:
            return None
    
    def TypeChar(data):
        try:
            return data.replace("'","")
        except:
            return None

    def TypeDate(data):
        try:
            return data
        except:
            return None
    
    def TypeDatetime(data):
        try:
            return data
        except:
            return None

安全性过滤内容也可同时写入其中

同时修改add_book

C:\Code\BookManagement\templates\management\add_book.html
def add_book(request):
    if request.user.is_authenticated:
        if request.method == "POST":
            try:
                name = cleandata.TypeChar(request.POST.get('name', ''))
                author = cleandata.TypeChar(request.POST.get('author', ''))
                price = cleandata.TypeFloat(request.POST.get('price', ''))
                publish_date = cleandata.TypeDate(request.POST.get('publish_date', ''))
                cateory = cleandata.TypeChar(request.POST.get('cateory', ''))
                create_datetime = cleandata.TypeDatetime(request.POST.get('create_datetime', ''))
                new_book = models.Book (
                    name = name,
                    author = author,
                    price = price,
                    publish_date = publish_date,
                    cateory = cateory,
                    create_datetime = create_datetime,
                )
                new_book.save()
                state='success'
            except:
                return redirect('/error/')
            return redirect('/book_list/')
    return render(request,"management/add_book.html")

添加error页面

发现还需要error页面,添加error页面

C:\Code\BookManagement\management\urls.py
from django.urls import URLPattern, path
from management import views

urlpatterns = [
    path('', views.index, name='homepage'),
    path('index/', views.index, name='homepage'),
    path('sign_up/', views.sign_up, name='sign_up'),
    path('login/', views.login, name='login'),
    path('logout/', views.logout, name='logout'),
    path('change_password/', views.change_password, name='change_password'),
    path('add_book/', views.add_book, name='add_book'),
    path('book_list/', views.book_list, name='book_list'),
    path('error/', views.error, name='error'),  # 添加error页面
]
C:\Code\BookManagement\management\views.py
def error(request):
    return render(request,"error.html")
C:\Code\BookManagement\templates\error.html
{% extends "management/navbar.html" %}

{% block title %}404{% endblock %}

{% block content %}
    <header class="jumbotron subhead" id="header-base">
        <div class="container">
            <h1 style="text-align: center;line-height:500px">给你一个错误自己领会</h1>
        </div>
    </header>
{% endblock %}

在这里插入图片描述

添加图书页面

继续添加图书

添加图书分类页面

添加图书分类页面

C:\Code\BookManagement\management\urls.py
from django.urls import URLPattern, path
from management import views

urlpatterns = [
    path('', views.index, name='homepage'),
    path('index/', views.index, name='homepage'),
    path('sign_up/', views.sign_up, name='sign_up'),
    path('login/', views.login, name='login'),
    path('logout/', views.logout, name='logout'),
    path('change_password/', views.change_password, name='change_password'),
    path('add_book/', views.add_book, name='add_book'),
    path('book_list/', views.book_list, name='book_list'),
    path('error/', views.error, name='error'),
    path('add_category/', views.add_category, name='add_category'),  # 添加分类页面
    path('category_list/', views.category_list, name='category_list'),  # 添加分类列表页面
]
C:\Code\BookManagement\management\views.py
def add_category(request):
    return render(request,"management/add_category.html")

def category_list(request):
    return render(request,"management/category_list.html")
C:\Code\BookManagement\templates\management\add_category.html
{% extends "management/navbar.html" %}

{% block title %}添加书籍分类{% endblock %}

{% block content %}
<div class="container" style="height: 100px;"></div>
<div class="container">
    <div class="row">
        <div class="col-md-10 col-md-offset-1">
            <form method="POST" role="form" class="form-horizontal">
                {% csrf_token %}
                <h1 class="form-signin-heading text-center">添加书籍分类</h1>
                <div class="form-group">
                    <div class="col-md-3">
                        <label for="id_parent_category" class="control-label">父类:</label>
                    </div>
                    <div class="col-md-9">
                        <input type="text" maxlength="200" class="form-control" id="id_parent_category" name="parent_category" autocomplete="no">
                    </div>
                </div>

                <div class="form-group">
                    <div class="col-md-3">
                        <label for="id_category" class="control-label">分类:</label>
                    </div>
                    <div class="col-md-9">
                        <input type="text" maxlength="200" class="form-control" id="id_category" required name="category" autocomplete="no" autofocus>
                    </div>
                </div>

                <div class="form-group">
                    <div class="col-md-3">
                    </div>
                    <div class="col-md-9">
                        <button class="btn btn btn-primary btn-block" type="submit">提交</button>
                    </div>
                </div>
            </form>
        </div>
    </div>
</div>
{% endblock %}
C:\Code\BookManagement\templates\management\category_list.html
{% extends "management/navbar.html" %}

{% block title %}书籍分类列表{% endblock %}

{% block content %}
    <div class="container" style="height: 100px;"></div>
    <div class="container">
        <div class="row">
            <div class="col-md-10 col-md-offset-1">
                <div class="list-group col-md-10">
                    <a href="/category_list/" class="list-group-item" id="id_category_all" style="text-align:center">全部分类</a>
                </div>
                <div class="list-group col-md-2">
                    <a href="/add_category/" class="list-group-item" id="id_category_all" style="text-align:center">添加分类</a>
                </div>
            </div>
            <div class ="col-md-10 col-md-offset-1">
                <table class="table table-hover">
                    <thead>
                        <tr>
                            <th>#</th>
                            <th>父类</th>
                            <th>分类</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for category in category_list %}
                            <tr>
                                <th>{{forloop.counter}}</th>
                                <th><a href="#">{{category.parent_category}}</a></th>
                                <th>{{category.category}}</th>
                            </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
{% endblock %}
C:\Code\BookManagement\templates\management\navbar.html
{% load static %}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>{% block title%}{% endblock %}</title>
    <link rel="stylesheet" type="text/css" href="{% static 'css/bootstrap.min.css' %}">
    <link rel="stylesheet" type="text/css" href="{% static 'css/base.css' %}">
	  <script type="text/javascript" src="{% static 'js/jquery.min.js' %}"></script>
	  <script type="text/javascript" src="{% static 'js/bootstrap.min.js' %}"></script>
</head>

<body>
    <nav class="navbar navbar-inverse navbar-fixed-top" role="navigatioin">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#navbar-collapse-basepage">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a href="/index/" class="navbar-brand">Library</a>
            </div>
            <div class="collapse navbar-collapse" id="navbar-collapse-basepage">
                <ul class="nav navbar-nav">
                    <li id="homepage">
                        <a href="/index/">主页</a>
                    </li>
                    <li id="book_list">
                        <a href="/book_list/">书籍列表</a>
                    </li>
                    <li id="category_list">
                        <a href="/category_list/">书籍分类列表</a>
                    </li>
                    
                </ul>
                <ul class="nav navbar-nav navbar-right">
                    {% if user %}
                        <li><a href="/change_password/">{{user}}</a></li>
                        <li><a href="/logout/">退出</a></li>
                    {% else %}
                        <li><a href="/sign_up/">注册</a></li>
                        <li><a href="/login/">登录</a></li>
                    {% endif %}
                </ul>
            </div>
    </nav>
{% block content %}
{% endblock %}
</body>

</html>

在这里插入图片描述
在这里插入图片描述

添加Category数据表

C:\Code\BookManagement\management\models.py
class Category(models.Model):
    parent_category = models.CharField(max_length=32, null=True, blank=True, verbose_name="父类")
    category = models.CharField(
        max_length=32, verbose_name='分类'
    )

要创建表的时候发现前面的category全部写错成了cateory,将涉及到的所有代码中的cateory全部替换为category

python manage.py makemigrations
python manage.py migrate
python manage.py runserver
PS C:\Code\BookManagement> python manage.py makemigrations
Migrations for 'management':
  management\migrations\0002_auto_20220503_1102.py
    - Create model Category
    - Remove field cateory from book
    - Add field category to book
PS C:\Code\BookManagement> python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, management, sessions
Running migrations:
  Applying management.0002_auto_20220503_1102... OK
C:\Code\BookManagement\management\views.py
def add_category(request):
    if request.user.is_authenticated:
        if request.method == "POST":
            try:
                parent_category = cleandata.TypeChar(request.POST.get('parent_category', ''))
                category = cleandata.TypeChar(request.POST.get('category',''))
                new_category = models.Category (
                    parent_category = parent_category,
                    category = category,
                )
                new_category.save()
                state='success'
            except:
                return redirect('/error/')
            return redirect('/category_list/')
    return render(request,"management/add_category.html")

def category_list(request):
    if request.user.is_authenticated:
        if request.method == "GET":
            category_list = models.Category.objects.all().only('parent_category','category')
            content={
                'category_list':category_list,
            }
            print(content)
            return render(request,"management/category_list.html",content)
    return render(request,"management/category_list.html")

在这里插入图片描述在这里插入图片描述

在添加图书的位置类型需要根据书籍分类列表中进行选择

在这里插入图片描述

修改添加图书页面

修改add_book页面前端和后端

C:\Code\BookManagement\templates\management\add_book.html

增加GET方法时return的参数

C:\Code\BookManagement\management\views.py
def add_book(request):
    if request.user.is_authenticated:
        if request.method == "GET":  # 增加GET方法
            category_list = models.Category.objects.all().only('category')
            content = {
                'category_list':category_list,  # 在content中添加category_list
            }
            return render(request,"management/add_book.html",content)  # 增加返回content
        if request.method == "POST":
            try:
                name = cleandata.TypeChar(request.POST.get('name', ''))
                author = cleandata.TypeChar(request.POST.get('author', ''))
                price = cleandata.TypeFloat(request.POST.get('price', ''))
                publish_date = cleandata.TypeDate(request.POST.get('publish_date', ''))
                cateory = cleandata.TypeChar(request.POST.get('cateory', ''))
                create_datetime = cleandata.TypeDatetime(request.POST.get('create_datetime', ''))
                new_book = models.Book (
                    name = name,
                    author = author,
                    price = price,
                    publish_date = publish_date,
                    cateory = cateory,
                    create_datetime = create_datetime,
                )
                new_book.save()
                state='success'
            except:
                return redirect('/error/')
            return redirect('/book_list/')
    return render(request,"management/add_book.html")

修改input为select,分类则变为可选项

在这里插入图片描述

添加前端与后端的实时交互JQuery AJAX

在添加图书位置若添加失败无任何提示信息,使用前端校验固然可以提示,但校验仍然需要以后端为准,添加前端与后端的实时交互

下载JQuery AJAX保持至BookManagement-management-static-jquery目录下

http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.12.4.min.js

修改navbar页面,添加JQuery AJAX和javascript块

C:\Code\BookManagement\templates\management\navbar.html
{% load static %}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>{% block title%}{% endblock %}</title>
    <link rel="stylesheet" type="text/css" href="{% static 'css/bootstrap.min.css' %}">
    <link rel="stylesheet" type="text/css" href="{% static 'css/base.css' %}">
	  <script type="text/javascript" src="{% static 'js/jquery.min.js' %}"></script>
	  <script type="text/javascript" src="{% static 'js/bootstrap.min.js' %}"></script>
</head>

<body>
    <nav class="navbar navbar-inverse navbar-fixed-top" role="navigatioin">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#navbar-collapse-basepage">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a href="/index/" class="navbar-brand">Library</a>
            </div>
            <div class="collapse navbar-collapse" id="navbar-collapse-basepage">
                <ul class="nav navbar-nav">
                    <li id="homepage">
                        <a href="/index/">主页</a>
                    </li>
                    <li id="book_list">
                        <a href="/book_list/">书籍列表</a>
                    </li>
                    <li id="category_list">
                        <a href="/category_list/">书籍分类列表</a>
                    </li>
                    
                </ul>
                <ul class="nav navbar-nav navbar-right">
                    {% if user %}
                        <li><a href="/change_password/">{{user}}</a></li>
                        <li><a href="/logout/">退出</a></li>
                    {% else %}
                        <li><a href="/sign_up/">注册</a></li>
                        <li><a href="/login/">登录</a></li>
                    {% endif %}
                </ul>
            </div>
    </nav>
{% block content %}
{% endblock %}
<script src="{% static 'jquery/jquery-1.12.4.min.js' %}"></script>
{% block javascript %}
{% endblock %}
</body>
</html>

修改添加图书页面

修改add_book页面,添加javascript

C:\Code\BookManagement\templates\management\add_book.html
C:\Code\BookManagement\management\views.py
from django.http import HttpResponse

def add_book(request):
    if request.user.is_authenticated:
        if request.method == "GET":
            category_list = models.Category.objects.all().only('category')
            content = {
                'category_list':category_list,
            }
            return render(request,"management/add_book.html",content)
        if request.method == "POST":
            try:
                name = cleandata.TypeChar(request.POST.get('name', ''))
                author = cleandata.TypeChar(request.POST.get('author', ''))
                price = cleandata.TypeFloat(request.POST.get('price', ''))
                publish_date = cleandata.TypeDate(request.POST.get('publish_date', ''))
                category = cleandata.TypeChar(request.POST.get('category', ''))
                create_datetime = cleandata.TypeDatetime(request.POST.get('create_datetime', ''))
                if name == "":
                    state='书名都不填的么'
                elif author == "":
                    state='作者都不填的么'
                elif price == "":
                    state='价格都不填的么'
                elif publish_date == "":
                    state='出版日期都不填的么'
                elif category == "":
                    state='类型都不选的么'
                else:
                    if models.Book.objects.filter(name=name,author=author):
                        state='已经添加过这本书籍了'
                    else:
                        models.Book.objects.create(
                            name = name,
                            author = author,
                            price = price,
                            publish_date = publish_date,
                            category = category,
                            create_datetime = create_datetime,
                        )
                        state='添加成功'
            except:
                state='添加失败'
            finally:
                return HttpResponse(state)
    return render(request,"management/add_book.html")

在这里插入图片描述在这里插入图片描述

在book_list页面中点击书名无法跳转到详情页面

在这里插入图片描述

修改添加书籍详情页面

添加书籍详情页面

C:\Code\BookManagement\management\urls.py
from django.urls import URLPattern, path
from management import views

urlpatterns = [
    path('', views.index, name='homepage'),
    path('index/', views.index, name='homepage'),
    path('sign_up/', views.sign_up, name='sign_up'),
    path('login/', views.login, name='login'),
    path('logout/', views.logout, name='logout'),
    path('change_password/', views.change_password, name='change_password'),
    path('add_book/', views.add_book, name='add_book'),
    path('book_list/', views.book_list, name='book_list'),
    path('error/', views.error, name='error'),
    path('add_category/', views.add_category, name='add_category'),
    path('category_list/', views.category_list, name='category_list'),
    path('book_detail/', views.book_detail, name='book_detail'),
]
C:\Code\BookManagement\management\views.py
def book_detail(request):
    return render(request,"management/book_detail.html")
C:\Code\BookManagement\templates\management\book_detail.html
{% extends "management/navbar.html" %}

{% block title %}书籍详情{% endblock %}

{% block content %}
<div class="container" style="height: 100px;"></div>
<div class="container">
    <div class="row">
        <div class="col-md-10 col-md-offset-1">
            <div role="form" class="form-horizontal">
                {% csrf_token %}
                <h1 class="form-signin-heading text-center">书籍详情</h1>
                <div class="form-group">
                    <div class="col-md-10">
                        <label for="id_name" class="control-label">{{book.name}}</label>
                    </div>
                </div>
                
                <div class="form-group">
                    <div class="col-md-10">
                        <label for="id_name" class="control-label">{{book.author}}</label>
                    </div>
                </div>
                
                <div class="form-group">
                    <div class="col-md-10">
                        <label for="id_name" class="control-label">{{book.category}}</label>
                    </div>
                </div>
                
                <div class="form-group">
                    <div class="col-md-10">
                        <label for="id_name" class="control-label">{{book.price}}</label>
                    </div>
                </div>
                
                <div class="form-group">
                    <div class="col-md-10">
                        <label for="id_name" class="control-label">{{book.publish_date}}</label>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

在这里插入图片描述

修改定位书籍信息

修改book_list在跳转至book_detail时带上书籍唯一id信息

C:\Code\BookManagement\templates\management\book_list.html
{% extends "management/navbar.html" %}

{% block title %}登录{% endblock %}

{% block content %}
    <div class="container" style="height: 100px;"></div>
    <div class="container">
        <div class="row">
            <div class="col-md-10 col-md-offset-1">
                <div class="list-group col-md-10">
                    <a href="/book_list/" class="list-group-item" id="id_category_all" style="text-align:center">全部图书</a>
                </div>
                <div class="list-group col-md-2">
                    <a href="/add_book/" class="list-group-item" id="id_category_all" style="text-align:center">添加书籍</a>
                </div>
            </div>
            <div class ="col-md-10 col-md-offset-1">
                <table class="table table-hover">
                    {% csrf_token %}
                    <thead>
                        <tr>
                            <th>#</th>
                            <th>书名</th>
                            <th>作者</th>
                            <th>出版日期</th>
                            <th>定价</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for book in book_list %}
                            <tr>
                                <th>{{forloop.counter}}</th>
                                <th><a href="/book_detail?id={{book.id}}">{{book.name}}</a></th>  <!-- 添加book.id跳转至书籍详情 -->
                                <th>{{book.author}}</th>
                                <th>{{book.publish_date}}</th>
                                <th>{{book.price}}</th>
                            </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
{% endblock %}
C:\Code\BookManagement\management\views.py
def book_list(request):
    if request.user.is_authenticated:
        if request.method == "GET":
            book_list = models.Book.objects.all().only('id','name','author','publish_date','price')  # 添加返回id
            content={
                'book_list':book_list,
            }
            return render(request,"management/book_list.html",content)
    return render(request,"management/book_list.html")
C:\Code\BookManagement\management\views.py
def book_detail(request):
    if request.user.is_authenticated:
        if request.method == "GET":
            id = cleandata.TypeNum(request.GET.get('id', ''))
            if id != '' and id != 0:
                book = models.Book.objects.get(id=id)
                content = {
                    'book':book,
                }
                return render(request,"management/book_detail.html",content)
    return render(request,"management/book_detail.html")

在这里插入图片描述

涉及POST请求的还有注册、登录、书籍分类,逐一添加提示信息

C:\Code\BookManagement\templates\management\sign_up.html
{% extends "management/navbar.html" %}

{% block title %}注册{% endblock %}

{% block content %}
    <div class="container" style="height: 100px;"></div>
    <div class="container">
        <div class="row">
            <div class="col-md-6 col-md-offset-3 col-sm-10 col-sm-offset-1">
                <div role="form" class="form-horizontal">
                    {% csrf_token %}
                    <h1 class="form-signin-heading text-center">请注册</h1>
                    <div style="height: 60px;">
                        <div class="alert alert-success" role="alert" id="id_alert_success" style="text-align: center;" hidden>
                            添加成功
                        </div>
                        <div class="alert alert-danger" role="alert" id="id_alert_danger" style="text-align: center;" hidden>
                            添加失败
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="id_username" class="col-md-3 control-label">用户名:</label>
                        <div class="col-md-9">
                            <input type="text" class="form-control" id="id_username" required name="username" autofocus>
                            <span class="help-block">用于登录,可以包括大小写字母和下划线。</span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="id_password" class="col-md-3 control-label">口令:</label>
                        <div class="col-md-9">
                            <input type="password" class="form-control" id="id_password" required name="password">
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="id_repassword" class="col-md-3 control-label">重复口令:</label>
                        <div class="col-md-9">
                            <input type="password" class="form-control" id="id_repassword" required name="repassword">
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="id_email" class="col-md-3 control-label">电子邮件:</label>
                        <div class="col-md-9">
                            <input type="email" class="form-control" id="id_email" required name="email">
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="col-md-9 col-md-offset-3">
                            <button class="btn btn btn-primary btn-block" type="submit" id="id_submit">注册</button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
{% endblock %}

{% block javascript %}
<script>
    $('#id_submit').click(function () {
		var csrf = $('input[name="csrfmiddlewaretoken"]').val();
        $.ajax({
            url:'',
            type:'post',
            data:{
                'username':$('#id_username').val(),
                'password':$('#id_password').val(),
                'repassword':$('#id_repassword').val(),
                'email':$('#id_email').val(),
                'csrfmiddlewaretoken': csrf,
            },
            success:function(state) {
                if (state == '注册成功') {
                    $('#id_alert_success').slideDown(500);
                    $('#id_alert_success').slideUp(1200);
                    $('#id_alert_success').text(state);
                    window.location.replace("/index/");
                }
                else {
                    $('#id_alert_danger').slideDown(500);
                    $('#id_alert_danger').slideUp(1200);
                    $('#id_alert_danger').text(state);
                }
            }
        })
    })
</script>
{% endblock %}
C:\Code\BookManagement\management\views.py
def sign_up(request):
    if request.method == "POST":
        try:
            username = request.POST.get('username', '')
            password = request.POST.get('password', '')
            repassword = request.POST.get('repassword', '')
            email = request.POST.get('email', '')
            if password == '' or repassword == '':
                state = '口令都不填的么'
            elif password != repassword:
                state = '你这两遍口令填的不同啊'
            else:
                if User.objects.filter(username=username):
                    state = '换个用户名,这个已经被占用了'
                else:
                    new_user = User.objects.create_user(
                        username=username, password=password, email=email)
                    new_user.save()
                    state = '注册成功'
                    return redirect("/index/")
        except:
            state = '注册失败'
        finally:
            return HttpResponse(state)
    return render(request, "management/sign_up.html")

在这里插入图片描述在这里插入图片描述

C:\Code\BookManagement\templates\management\login.html
{% extends "management/navbar.html" %}

{% block title %}登录{% endblock %}

{% block content %}
    <div class="container" style="height: 100px;"></div>
    <div class="container">
        <div class="row">
            <div class="col-md-6 col-md-offset-3 col-sm-10 col-sm-offset-1">
                <div role="form" class="form-horizontal">
                    {% csrf_token %}
                    <h1 class="form-signin-heading text-center">请登录</h1>
                    <div style="height: 60px;">
                        <div class="alert alert-success" role="alert" id="id_alert_success" style="text-align: center;" hidden>
                            添加成功
                        </div>
                        <div class="alert alert-danger" role="alert" id="id_alert_danger" style="text-align: center;" hidden>
                            添加失败
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="id_username" class="col-md-3 control-label">用户名:</label>
                        <div class="col-md-9">
                            <input type="text" class="form-control" id="id_username" required name="username" autofocus>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="id_password" class="col-md-3 control-label">口令:</label>
                        <div class="col-md-9">
                            <input type="password" class="form-control" id="id_password" required name="password">
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="col-md-9 col-md-offset-3">
                            <button class="btn btn btn-primary btn-block" type="submit" id="id_submit">登录</button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
{% endblock %}

{% block javascript %}
<script>
    $('#id_submit').click(function () {
		var csrf = $('input[name="csrfmiddlewaretoken"]').val();
        $.ajax({
            url:'',
            type:'post',
            data:{
                'username':$('#id_username').val(),
                'password':$('#id_password').val(),
                'csrfmiddlewaretoken': csrf,
            },
            success:function(state) {
                if (state == '登录成功') {
                    $('#id_alert_success').slideDown(500);
                    $('#id_alert_success').slideUp(1200);
                    $('#id_alert_success').text(state);
                    window.location.replace("/index/");
                }
                else {
                    $('#id_alert_danger').slideDown(500);
                    $('#id_alert_danger').slideUp(1200);
                    $('#id_alert_danger').text(state);
                }
            }
        })
    })
</script>
{% endblock %}
C:\Code\BookManagement\management\views.py
def login(request):
    if request.method == "POST":
        username = request.POST.get('username', '')
        password = request.POST.get('password', '')
        if username and password:
            user = auth.authenticate(username=username, password=password)
            if user is not None:
                auth.login(request, user)
                state = '登录成功'
                return HttpResponse(state)
            else:
                state = '用户不存在或口令错误'
                return HttpResponse(state)
    return render(request, "management/login.html")

在这里插入图片描述
在这里插入图片描述

修改用户未登录时前端显示错误问题

未登录时用户位置显示AnomymousUser……

在这里插入图片描述

C:\Code\BookManagement\templates\management\navbar.html
{% load static %}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>{% block title%}{% endblock %}</title>
    <link rel="stylesheet" type="text/css" href="{% static 'css/bootstrap.min.css' %}">
    <link rel="stylesheet" type="text/css" href="{% static 'css/base.css' %}">
	  <script type="text/javascript" src="{% static 'js/jquery.min.js' %}"></script>
	  <script type="text/javascript" src="{% static 'js/bootstrap.min.js' %}"></script>
</head>

<body>
    <nav class="navbar navbar-inverse navbar-fixed-top" role="navigatioin">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#navbar-collapse-basepage">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a href="/index/" class="navbar-brand">Library</a>
            </div>
            <div class="collapse navbar-collapse" id="navbar-collapse-basepage">
                <ul class="nav navbar-nav">
                    <li id="homepage">
                        <a href="/index/">主页</a>
                    </li>
                    <li id="book_list">
                        <a href="/book_list/">书籍列表</a>
                    </li>
                    <li id="category_list">
                        <a href="/category_list/">书籍分类列表</a>
                    </li>
                    
                </ul>
                <ul class="nav navbar-nav navbar-right">
                    {% if username %}  # 将原有的变量名user修订为uesrname
                        <li><a href="/change_password/">{{username}}</a></li>
                        <li><a href="/logout/">退出</a></li>
                    {% else %}
                        <li><a href="/sign_up/">注册</a></li>
                        <li><a href="/login/">登录</a></li>
                    {% endif %}
                </ul>
            </div>
    </nav>
{% block content %}
{% endblock %}
<script src="{% static 'jquery/jquery-1.12.4.min.js' %}"></script>
{% block javascript %}
{% endblock %}
</body>
</html>
C:\Code\BookManagement\management\views.py
def index(request):
    if request.user.is_authenticated:
        username = request.user  # 将原有的变量名user修订为uesrname
        content={
            'username':username,
        }
        return render(request, "management/index.html",content)
    return render(request, "management/index.html")

重新选择皮肤

页面微丑,选个合适的皮肤

目前最新的是Bootstrap5,下载Bootstrap5

C:\Code\BookManagement\management\static

选择examples中的样例,选择样例
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

全面修订样式和前端体验

修订样式并稍微修订前端体验,当前代码位于《Django开发从入门到实践》学习笔记(代码)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

部署上线

操作系统版本:CentOS Linux release 8.5.2111
Docker版本:Docker version 20.10.12, build e91ed57
Docker容器版本:Ubuntu 22.04 LTS

安装

# 获取ubuntu镜像
sudo docker pull ubuntu
# 创建ubuntu容器并映射端口8888/8000命令为BookManagement
sudo docker run --name BookManagement -p8888:8888 -p8000:8000 -it -id ubuntu /bin/bash
# 进入BookManagement容器
sudo docker exec -it BookManagement /bin/bash
# apt-get更新
apt-get update
# 安装python3、pip3、nginx
apt-get -y install python-dev-is-python3 python3-pip nginx
# 安装uwsgi、django3
pip install uwsgi django==3.0.6

配置

修改/etc/BookManagement/BookManagement/settings.py文件

/etc/BookManagement/BookManagement/settings.py
# 上线后不能为调试模式,关闭调试模式
DEBUG = False
# 未配置时默认本地访问,上线后需要开放远程访问,可配置为具体的目标IP地址或开放远程访问
ALLOWED_HOSTS = ['*']
# 原有配置
STATIC_URL = '/static/'
# 添加BASE_DIR配置以指向STATIC_URL路径
STATIC_ROOT = os.path.join(BASE_DIR,"/etc/BookManagement/management/")
# 将Django项目从本地复制到服务器宿主机
scp -r C:\Code\BookManagement root@0.0.0.0:/etc/
# 将Django项目从服务器宿主机复制到Docker容器内
sudo docker cp /etc/BookManagement BookManagement:/etc/
# 进入BookManagement项目
cd /etc/BookManagement
# 将配置的静态文件收集到STATIC_ROOT中
python manage.py collectstatic

若使用Django+uwsgi访问,可使用http路由访问http://0.0.0.0:8888,映射的8888端口用于访问http路由方式部署的uwsgi,确定使用http路由方式访问则此时的状态后台运行Ctrl+Z即可

# --chdir配置项目绝对路径、--wsgi-file配置wsgi.py依据项目绝对路径的相对路径、--static-map配置/static/绝对路径
uwsgi --http-socket :8888 --chdir /etc/BookManagement/ --wsgi-file BookManagement/wsgi.py --static-map=/static/=/etc/BookManagement/management/static --master --process 4 --workers 4

若使用Django+uwsgi+nginx访问,可使用socket路由访问nginx端口,映射的8000端口用于访问socket路由方式部署的uwsgi访问后的nginx反向代理,上述访问需要Ctrl+C中断或ps -ef | grep uwsgi查看id后中断

# --chdir配置项目绝对路径、--wsgi-file配置wsgi.py依据项目绝对路径的相对路径、--static-map配置/static/绝对路径
uwsgi --socket :8888 --chdir /etc/BookManagement/ --wsgi-file BookManagement/wsgi.py --static-map=/static/=/etc/BookManagement/management/static --master --process 4 --workers 4
# 配置nginx.conf
cat >/etc/nginx/nginx.conf
# 配置nginx启动用户
user root;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 768;
    # multi_accept on;
}

http {
    # 配置文件类型值
    include mime.types;  # 包含静态文件解析方式
    default_type  application/octet-stream;
    server {
        listen     8887;  # 配置nginx监听端口
        server_name  127.0.0.1;  # 配置服务器地址,若为本地则为127.0.0.1或localhost
        charset UTF-8;
        access_log   /var/log/nginx/access.log;  # 配置访问日志地址
        error_log    /var/log/nginx/error.log;  # 配置错误日志地址
        location / {
            uwsgi_pass 127.0.0.1:8888;  # 传递每一个请求给绑定到8888端口并使用uwsgi协议的服务器
            include /etc/nginx/uwsgi_params;  # 包含uwsgi_params
        }
        location /static {  # 配置/static中css、js路径
            expires 30d;
            autoindex on;
            add_header Cache-Control private;
            alias /etc/BookManagement/management;  # /static的上层绝对路径
        }
    }
}

启动nginx服务

service nginx restart

访问

http://0.0.0.0:8000

在这里插入图片描述

参考链接:
https://uwsgi-docs-zh.readthedocs.io/zh_CN/latest/WSGIquickstart.html
https://blog.csdn.net/weixin_42134789/article/details/115713572