首页 > 技术文章 > Django实现简单的用户添加、删除、修改等功能

maoruqiang 2019-06-06 23:49 原文

一. Django必要的知识点补充

1. templates和static文件夹及其配置

  1.1 templates文件夹

  所有的HTML文件默认都放在templates文件夹下。

  1.2 static文件夹

  所有的静态文件(css,js,前端第三方类库)默认都放在static文件夹下。我们需要手动创建static文件夹(跟app处于同级目录,每个app文件夹里面也可以有自己的static文件夹),然后里面再建两个文件夹:css和js)。

  首先HTML页面访问外部资源有两个方式,一是cdn,二是本地。当我们服务端用的本地的时候,客户端是访问不到的(如果说本地静态文件夹路径是D:\mydjango/static,客户端访问时可能就会变成127.0.0.1/8080/mydjango/static,自然是访问不到。)

  为了让客户端能访问到静态文件(比如我们用本地导入的Bootstrap),我们需要修改Django的settings.py:

  1. 拉到settings.py最下面

  2. 在其下面添加STATICFILES_DIRS = [ ],里面存放静态文件夹的路径。

STATIC_URL = '/static/' 
#接口前缀,规定了你HTML界面导入静态文件的路径前缀,/变量名/:变量名随意取
#但默认情况下接口前缀跟文件夹名字一样
        
#静态文件设置
STATICFILES_DIRS = [
    #静态文件夹路径,可以有多个,因为每个app也可以有自己的static文件夹
    os.path.join(BASE_DIR, 'static') 
]
        
#暴露给外界,能够访问服务器静态文件下所有的资源
#STATICFILES_DIRS里面可以写多个静态文件夹的路径
#浏览器访问时会依次从静态文件夹路径查找资源,找到就停止,如果都没找到就报错,

   3. 将HTML文件中导入静态文件的地方路径也稍作修改,路径开始都换成接口前缀,后面跟static文件下你要导入的文件的相对路径即可。

2. 关于form表单提交数据

  2.1 提交数据的两种方式

  第一种:submit

<input type="submit">

    第二种:button按钮

<button>button</button>

  2.2 form表单提交数据的地址指定方式

   首先地址是由action属性来控制的。

  第一种方式:全路径

<form action="http://127.0.0.1:8000/login/">

   第二种方式:只写路径后缀(浏览器会自动拿当前页面的host、ip帮你补全路径)

<form action="/login/">

   第三种方式:不写,默认是提交至当前页面。

  注意:form表单默认是GET请求,需要向后端提交form表单数据时,我们需要通过method属性改为POST。

<form action="/login/" method='POST'>

  单单这样还不够,为了POST请求不报错,我们需要先将Django的settings.py中注释掉一个中间件。

  如果不注释的话可能会出现以下问题:

3. 后端获取前端数据的方法

  首先我们需要能够判断浏览器是单纯想获取页面信息还是有数据提交给我们。这就需要用到request.method方法,它能获取当前客户端的请求方式(GET、POST)。

def login(request):
    print(request.method)
    if request.method == 'POST':
        print(request.POST) #可以看做是存放客户端POST请求提交的所有数据的字典{key:value}
        # request.POST:< QueryDict: {'username': ['jason'], 'password': ['123']} >
    print(request.POST.get('username')) #虽然value是列表,但是默认取其中的最后一个数据
    print(request.POST['username']) #拿到的也同.get一样,不推荐使用该方法获取数据
    print(request.POST.getlist('username')) #一次性获取value列表所有数据
    return HttpResponse('OK')
    print(request.GET)  #跟request.POST获取数据方式一样
    return render(request, 'login.html')            

   注意:获取value列表里面所有元素需要使用getlist,应用场景:用户的爱好--多选框

get只能拿到value列表的最后一个元素。前端GET请求最多携带数据为4KB。

  还有一点要提的是,不论你的请求方式是GET或者是POST,只要你的路径携带了信息,后端都可以通过request.GET来得到(比如:127..0.1:8080/index/?id=1,我们可以通过request.GET.get('id')拿到id)。这就意味着前端请求方式是POST得时候,后端也是可以通过request.GET来得到消息,举个实例。

  当我们一些数据想要给后端,但是又不想让其显示在前端界面的时候,有两种方式可以实现。

  方式一:将id放在form表单action的URL后面

<form action="/edit/?edit_id={{ user_obj.pk }}" method="post">

  方式二:利用input隐藏

<input type="hidden" name="edit_id" value="{{ user_obj.pk }}">

 二. Django连接数据库

  Django的settings.py里面提供了连接数据库的入口,要实现连接不同的数据库,只要修改其中的参数等信息即可。

1. sqlite3数据库

  是Django自带的一个小型数据库,可以用来做本地测试,如果数据量不大的话。

2. 连接MySQL数据库

  1. 修改配置文件

  修改上述DATABASES中的参数(键必须都是大写)

  2. 告诉django用pymysql替换它默认的mysql_db模块连接数据库

  因为mysql_db现在已经没用了,所以需要替换模块。

  在项目文件夹下的__init__.py或者是应用文件夹下的__init__.py中加入以下语句。

#加下列语句,固定写法
import pymysql
pymysql.install_as_MySQLdb()

  3. 点击pycharm右侧的database,选择要连接的数据库

  4. 最后一步准备

  这样数据库就成功连接上了,如果中途没出现什么意外的话。

3. 数据库迁移(同步)命令

   Django的ORM虽然不会自动帮我们创建库,但是会帮我们自动创建表,然而创建的过程还是需要我们配合的,并非全自动。

  还需要在命令行窗口(比如pycharm里的terminal)输入以下命令:

python3 manage.py makemigrations #数据库变动的记录(并不会帮你创建表)
python3 manage.py migrate  #将你的数据库变动同步到数据库中(这下才是真正创建表了)

   数据库迁移命令执行完毕后,表创建完成了,不过你可能会发现它帮我们创建了其他的表,不要慌,正常现象。

  注意:

  • 数据库迁移记录都存放在migrations文件夹下。
  • tools选项中的Run manage.py Task敲命令更方便,因为有提示,而且不需要输入前面的python3 manage.py。(当然前期不推荐这么干,要不然完整命令都忘了,面试被问到了咋整)
  • 只要修改了模型层(models.py)的与表相关的任何数据,都必须重新执行数据库迁移命令。
  • 一个Django项目用一个库,不要多个Django项目共用一个库!!!

三. Django中的ORM(初级知识)

 1. ORM概念

  对象关系映射(英语:(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换  。从效果上说,它其实是创建了一个可在编程语言里使用的--“虚拟对象数据库”。

  在ORM中,每一个类都映射数据库中的一张表。ORM的类都写在models.py中。

类    》》》 表
对象  》》》 表记录
对象的属性 》》》一条记录某个字段对应的值

 2. ORM对数据库的增删改查

  操作数据库,无非就是增删改查,为了更好的演示,这里定义一个ORM类,然后假设前后端数据交互已完成,username和password均是从前端拿到的数据。

  这里先提一个QuerySet对象,Django操作数据库时,查询的all()和filter()方法返回的是QuerySet对象,有点像列表里面存放一个个对象,它可以用.query的方法获取其内部的mysql语句。如果要获取数据对象的话,可以用索引取,但是不推荐这么做,因为可能会报错,通常我们用QuerySet.first()等方法取其中的数据对象。

class User(models.Model):
    # user表的主键字段名就是id,其实可以不写,因为你不写时Django默认会帮你创建一个字段名为id的主键
    id = models.AutoField(primary_key=True)
    # varchar(32) name字段是varchar(32)   CharField在定义的时候必须要加max_length参数
    name = models.CharField(max_length=32)
    # varchar(16) name字段是varchar(32)   CharField在定义的时候必须要加max_length参数
    password = models.CharField(max_length=16)

   2.1 增

  方式一:

user_obj = models.User.objects.create(name=username, 
password=password) #返回当前的数据对象本身

   方式二:

user_obj = models.User(name=username, password=password)
user_obj.save() # 对象调用save方法保存至数据库

   2.2 查

  查全部数据:

user_list = models.User.objects.all() 
print(user_list)
print(user_list.query) #只要是QuerySet对象,就能用.query获取它内部的MySQL语句

  根据条件查询:

res = models.User.objects.filter(id=delete_id) 
#这样回来的是QuerySet对象,如果条件不存在返回空的QuerySet对象 res = models.User.objects.filter(id=delete_id).first()
#取出里面的第一个对象,虽然可以索引取,但是不推荐使用,而起不支持负索引取值

  根据条件查询直接拿一个数据对象(该方法不推荐使用,因为存在报错的情况)

res = models.User.objects.get(id=edit_id)  #如果id不存在会直接报错

   注意:get和filter相比,get能直接拿回一个数据对象,但是查询条件不满足时会报错。而filter查询条件满足或者不满足时返回的都是QuerySet对象,可以通过.first()、.last()取其中的数据对象,不存在报错的情况。所以一般选择用filter方法。

  2.3 删

models.User.objects.filter(id=delete_id).delete() 
#会将该QuerySet里面的数据对象都删除掉(会同步到数据库)

  2.4 改

#方式一(推荐使用该方式):
models.User.objects.filter(id=edit_id).update(name=username, password=password)

#方式二:
user_obj = models.User.objects.filter(id=edit_id).first()
user_obj.name = username
user_obj.save()

  注意:QuerySet点语法,点删除和修改都会作用于对象内部所有的数据对象,类似于批量操作。

所以想要操作单个数据对象时,最好查时用能唯一标识一条数据的条件。

四. 简单实现用户的添加、删除、修改操作

   现在我们数据库连接也会了,ORM也稍微知道了一点用法,就可以写一点东西来让知识点印象更深刻。

1. 用户的注册

   首先思路是用户在浏览器输入用户名、密码,点注册按钮后,将输入的数据提交给后端,后端从数据库找相应的用户信息是否存在。存在则返回用户已存在,不存在则完成用户的创建并返回注册成功。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>register</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .c1 {
            margin-top: 50px;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-4 col-md-offset-4 c1">
            <h2 class="text-center">注册</h2>
            <form action="" method="post">
                <p>username:<input type="text" name="username" class="form-control"></p>
                <p>password:<input type="password" name="password" class="form-control"></p>
                <input type="submit" value="注册" class="btn btn-success">
            </form>
        </div>
    </div>
</div>
</body>
</html>
regist.html
def register(request):
    if request.method == 'POST':
        name = request.POST.get('username')
        password = request.POST.get('password')
        user_obj = models.User.objects.filter(name=name, password=password).first()
        if not user_obj:
            models.User.objects.create(name=name, password=password)
            return HttpResponse('注册成功')
        return HttpResponse('该用户已存在')
    return render(request, 'register.html')
register视图函数

 2. 登录

  思路跟注册异曲同工,也是用户在浏览器输入用户名、密码,点点击登录按钮后数据提交至后端,后端从数据库找相应用户信息,信息存在则返回登录成功,否则返回用户不存在。(如何明确告诉用户是用户名错误或者密码错误?可以自己尝试)。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
{#    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>#}
{#    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">#}
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
    <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
    <style>
        .c1 {
            margin-top: 50px;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-4 col-md-offset-4 c1">
            <h2 class="text-center">登录</h2>
            <form action="" method="post">
                <p>username:<input type="text" name="username" class="form-control"></p>
                <p>password:<input type="password" name="password" class="form-control"></p>
                <input type="submit" value="登录" class="btn btn-success">
            </form>
        </div>
    </div>
</div>
</body>
</html>
login.html
def login(request):
    if request.method == 'POST':
        name = request.POST.get('username')
        password = request.POST.get('password')
        user_obj = models.User.objects.filter(name=name, password=password).first()
        if not user_obj:
            return HttpResponse('该用户不存在')
        return HttpResponse('登录成功')
    return render(request, 'login.html')
login视图函数

 

3. 管理员添加、删除、编辑用户信息

  首先要有一个管理员界面,管理员界面除了用户信息,还应该有添加、删除、编辑等按钮,点击相应的按钮就能执行相应的功能,这里按钮采用a标签(用bootstrap装饰成按钮的样子),不同按钮对应不同的URL。

  3.1 添加新用户

   这里采用最简单的方式,点击添加按钮,跳转至register视图函数,注册成功再重定向至用户管理页面。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>manage_user</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .c1 {
            display: inline-block;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row" style="margin-top: 50px">
        <div class="col-md-6 col-md-offset-3">
            <a href="/register/" class="btn btn-success" style="margin-right: 75px">添加</a>
            <h2 class="text-center c1">用户管理</h2>
        </div>
    </div>
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <table class="table table-bordered table-striped table-hover">
                <thead>
                    <tr>
                        <th class="text-center">id</th>
                        <th class="text-center">name</th>
                        <th class="text-center">password</th>
                        <th class="text-center">operation</th>
                    </tr>
                </thead>
                <tbody>
                    {% for user_obj in user_list %}
                        <tr class="text-center">
                            <td>{{user_obj.id}}</td>
                            <td>{{user_obj.name}}</td>
                            <td>{{user_obj.password}}</td>
                            <td><a href="" class="btn btn-primary">编辑</a>
                            <a href="" class="btn btn-danger">删除</a></td>
                        </tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</div>
</body>
</html>
只有添加按钮生效的html
# 注册视图函数
def register(request):
    if request.method == 'POST':
        # 获取前端提交的用户名
        name = request.POST.get('username')
        # 获取前端提交的用户密码
        password = request.POST.get('password')
        # 查找出相应用户信息,filter返回的也是QuerySet对象,first方法取出其中第一个数据对象,可以为空
        user_obj = models.User.objects.filter(name=name, password=password).first()
        # 用户不存在则在数据库中创建相应用户信息记录,并重定位至管理员界面
        if not user_obj:
            models.User.objects.create(name=name, password=password)
            return redirect('/manage_user/')
        return HttpResponse('该用户已存在')
    return render(request, 'register.html')
修改过后的注册视图函数
# 用户管理界面视图函数
def manage_user(request):
    # 取出所有用户信息,all方法取出来的是QuerySet对象
    user_list = models.User.objects.all()
    # render渲染前端页面,locals将当前函数所有变量都发送至前端
    return render(request, 'manage_user.html', locals())
管理员视图函数

   3.2 删除用户

  相比编辑用户,删除用户显得简单点,那就先讲删除吧。当有多条用户记录时,如果让后端知道我点删除是想删除哪条数据呢,这是一个问题。所以我们要想办法把要删除的用户的一个标识告诉后端,比如说我一点删除,向后端提交数据时顺手把要删除的用户id带给它。这就用到了上面一.3中提到的前端向后端隐式提交数据的两种方式:1. 用input标签隐藏  2. 放在URL里带给后端。

  这里采用第二种方法。(/delete_user/?user_id={{ user_obj.id }}) 注意:URL后面携带的数据有多个时,用&隔开。

# 删除用户信息视图函数
def delete_user(request):
    user_id = request.GET.get('user_id')
    models.User.objects.filter(id=user_id).delete()
    return redirect('/manage_user/')
删除用户视图函数

  3.3 编辑用户信息

  编辑用户信息,同理,我们需要得到用户的唯一标识,这里也采用跟删除用户同样的方法。当我们把用户信息拿出来后,要先把数据渲染至前端(数据不给看还怎么编辑),然后想要修改的数据需要输入(一提到这个就只有form表单的input了,然后input还有个value属性,那么我们就可以定义input,然后将value设置为原用户相应的信息,一举两得)。

  3.4 代码

  应用文件夹下:

from django.shortcuts import render, HttpResponse, redirect
from app01 import models
# Create your views here.


# 登录视图函数
def login(request):
    if request.method == 'POST':
        name = request.POST.get('username')
        password = request.POST.get('password')
        user_obj = models.User.objects.filter(name=name, password=password).first()
        if not user_obj:
            return HttpResponse('该用户不存在')
        return HttpResponse('登录成功')
    return render(request, 'login.html')


# 注册视图函数
def register(request):
    if request.method == 'POST':
        # 获取前端提交的用户名
        name = request.POST.get('username')
        # 获取前端提交的用户密码
        password = request.POST.get('password')
        # 查找出相应用户信息,filter返回的也是QuerySet对象,first方法取出其中第一个数据对象,可以为空
        user_obj = models.User.objects.filter(name=name, password=password).first()
        # 用户不存在则在数据库中创建相应用户信息记录,并重定位至管理员界面
        if not user_obj:
            models.User.objects.create(name=name, password=password)
            return redirect('/manage_user/')
        return HttpResponse('该用户已存在')
    return render(request, 'register.html')


# 用户管理界面视图函数
def manage_user(request):
    # 取出所有用户信息,all方法取出来的是QuerySet对象
    user_list = models.User.objects.all()
    # render渲染前端页面,locals将当前函数所有变量都发送至前端
    return render(request, 'manage_user.html', locals())


# 删除用户信息视图函数
def delete_user(request):
    user_id = request.GET.get('user_id')
    models.User.objects.filter(id=user_id).delete()
    return redirect('/manage_user/')


# 编辑用户信息视图函数
def edit_user(request):
    user_id = request.GET.get('user_id')
    user_obj = models.User.objects.filter(id=user_id).first()
    if request.method == 'POST':
        name = request.POST.get('username')
        password = request.POST.get('password')
        models.User.objects.filter(id=user_id).update(name=name, password=password)
        return redirect('/manage_user/')
    return render(request, 'edit_user.html', locals())
视图函数 views.py
from django.db import models

# Create your models here.


class User(models.Model):
    name = models.CharField(max_length=32)
    password = models.CharField(max_length=32)
模型层 models.py
import pymysql
pymysql.install_as_MySQLdb()
__init__.py

  项目文件夹下:

"""edit_user2 URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', views.login),
    url(r'^register/', views.register),
    url(r'^manage_user/', views.manage_user),
    url(r'^delete_user/', views.delete_user),
    url(r'^edit_user/', views.edit_user),
]
路由--视图函数对应关系urls.py
"""
Django settings for edit_user2 project.

Generated by 'django-admin startproject' using Django 1.11.11.

For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'm7hja%y&udo+^wbikt7e#9df5wk##-+vmfh3^(8i5!_ll(6=vx'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'edit_user2.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, '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',
            ],
        },
    },
]

WSGI_APPLICATION = 'edit_user2.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'user_db',
        'HOST': '127.0.0.1',
        'PORT': 3306,
        'USER': 'root',
        'PASSWORD': 'root'
    }
}


# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

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

   templaets文件夹下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
{#    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>#}
{#    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">#}
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
    <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
    <style>
        .c1 {
            margin-top: 50px;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-4 col-md-offset-4 c1">
            <h2 class="text-center">登录</h2>
            <form action="" method="post">
                <p>username:<input type="text" name="username" class="form-control"></p>
                <p>password:<input type="password" name="password" class="form-control"></p>
                <input type="submit" value="登录" class="btn btn-success">
            </form>
        </div>
    </div>
</div>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>register</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .c1 {
            margin-top: 50px;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-4 col-md-offset-4 c1">
            <h2 class="text-center">注册</h2>
            <form action="" method="post">
                <p>username:<input type="text" name="username" class="form-control"></p>
                <p>password:<input type="password" name="password" class="form-control"></p>
                <input type="submit" value="注册" class="btn btn-success">
            </form>
        </div>
    </div>
</div>
</body>
</html>
register.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>manage_user</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <style>
        .c1 {
            display: inline-block;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row" style="margin-top: 50px">
        <div class="col-md-6 col-md-offset-3">
            <a href="/register/" class="btn btn-success" style="margin-right: 75px">添加</a>
            <h2 class="text-center c1">用户管理</h2>
        </div>
    </div>
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <table class="table table-bordered table-striped table-hover">
                <thead>
                    <tr>
                        <th class="text-center">id</th>
                        <th class="text-center">name</th>
                        <th class="text-center">password</th>
                        <th class="text-center">operation</th>
                    </tr>
                </thead>
                <tbody>
                    {% for user_obj in user_list %}
                        <tr class="text-center">
                            <td>{{user_obj.id}}</td>
                            <td>{{user_obj.name}}</td>
                            <td>{{user_obj.password}}</td>
                            <td><a href="/edit_user/?user_id={{ user_obj.id }}" class="btn btn-primary">编辑</a>
                            <a href="/delete_user/?user_id={{ user_obj.id }}" class="btn btn-danger">删除</a></td>
                        </tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</div>
</body>
</html>
manage_user.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>edit_user</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-4 col-md-offset-4">
            <h2 class="text-center">编辑用户</h2>
            <form action="/edit_user/?user_id={{ user_obj.id }}" method="post">
                <p>username:<input type="text" name='username' value="{{ user_obj.name }}" class="form-control"></p>
                <p>password:<input type="text" name='password' value="{{ user_obj.password }}" class="form-control"></p>
                <input type="submit" value="确认修改" class="btn btn-success">
                <a href="/manage_user/" class="btn btn-danger">取消</a>
            </form>
        </div>
    </div>
</div>
</body>
</html>
edit_user.html

 

推荐阅读