案例:员工管理系统

创建项目

  • 删除pycharm自动增加的
  • 删除templates文件

创建app

两种方式创建app,可以在pycharm的终端输入,也可以先pycharm帮助执行一个manage.py

  1. 终端输入
    1
    python manage.py startapp app01
  2. 使用pycharm
  • 相当于pycharm帮助执行了一个manage.py
  • 直接输入startapp <文件名>即可创建

注册app

  • settings.py中注册app

设计表结构

  • 新建用户表
  • 新建部门表
  • 将用户表和部门表进行关联
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    from django.db import models

    class Department(models.Model):
    """部门表"""
    # id = models.BigAutoField(verbose_name="ID", primary_key=True)
    title = models.CharField(verbose_name='标题', max_length=32)


    class UserInfo(models.Model):
    """员工表"""
    name = models.CharField(verbose_name="姓名", max_length=16)
    password = models.CharField(verbose_name="密码", max_length=64)
    age = models.IntegerField(verbose_name="年龄")
    account = models.DecimalField(verbose_name="账户余额", max_digits=10, decimal_places=2, default=0)
    create_time = models.DateTimeField(verbose_name="入职时间")
    # 无约束
    # depart_id = models.BigIntegerField(verbose_name="部门ID")

    # 部门删除,部门id列置空
    # depart_id = models.ForeignKey(to="Department", to_fields="id",null=True, blank=True, on_delete=models.SET_NULL)

    # (对部门id进行约束) to 与那张表关联 to_fields 表中哪一列有关联, 级联删除此行
    depart_id = models.ForeignKey(to="Department", to_fields="id", on_delete=models.CASCADE)
    gender_choices = (
    (1, "男"),
    (2, "女")
    )
    gender = models.SmallIntegerField(verbose_name="性别",choices=gender_choices)

在MySQL中生成表

  • 工具连接MySQL生成数据库
    1
    create database djtest; 
  • 修改settings.py数据库配置
1
2
3
4
5
6
7
8
9
10
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'djtest',
'USER': 'root',
'PASSWORD': 'root',
'HOST': '127.0.0.1',
'PORT': 3306
}
}
  • 基于django命令生成数据库的表

    • 命令行执行
1
2
python manage.py makemigrations
python manage.py migrate

​ manage.py中执行

1
2
makemigrations
migrate
  • 进入数据库查看

静态文件管理

  • 放入文件

列表页面布局

  • urls.py

  • ```views.py``

  • depart_list.html

  • 页面效果

从数据库获取数据

  • 如下(以下两个部门为数据库预先输入的)

增删改页面布局设计

  • 修改depart_list.html
  • urls.py中添加path和```views.py``中写入
  • depart_add.html

添加部门

删除部门

  • 列表页面删除按钮添加链接

修改部门

模板的继承

  • 当我们每个页面都需要保留导航栏的时候,我们对每个HTML都写了一个导航栏,这样有些麻烦,修改时文件过多不易修改,因此我们可以选择模板。
  • 模板的定义
  • 将我们的插件写在模板中

layout.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'plugins/bootstrap3/css/bootstrap.min.css' %}">
</head>
<body>
<h1>标题</h1>
{% block content %}{% endblock %}
<h1>结尾</h1>
<script src="{% static 'js/jquery-3.6.1.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap3/js/bootstrap.min.js' %}"></script>
</body>
</html>
  • 继承模板

为了避免一个页面加载不必要的插件,可以多写几个模板,在需要的位置进行填充

1
2
3
4
5
{% extends 'layoyt.html' %}

{% block content %}
<h1>首页<h1>
{% endblock %}

模板的继承

  • 当我们每个页面都需要保留导航栏的时候,我们对每个HTML都写了一个导航栏,这样白那些麻烦,修改时文件过多不易修改,因此我们可以选择模板。

  • 模板的定义

  • 将我们的插件写在模板中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{% static 'plugins/bootstrap3/css/bootstrap.min.css' %}">
    </head>
    <body>
    <h1>标题</h1>
    {% block content %}{% endblock %}
    <h1>结尾</h1>
    <script src="{% static 'js/jquery-3.6.1.min.js' %}"></script>
    <script src="{% static 'plugins/bootstrap3/js/bootstrap.min.js' %}"></script>
    </body>
    </html>
  • 继承模板

    1
    2
    3
    4
    5
    {% extends 'layoyt.html' %}

    {% block content %}
    <h1>首页<h1>
    {% endblock %}
  • 为了避免一个页面加载不必要的插件,可以多写几个模板,在需要的位置进行填充

案例:员工管理系统(部门管理)优化

将导航部分写入模板,列表,添加,编辑页面进行集成

  • layoyt.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    {% load static %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{% static 'plugins/bootstrap3/css/bootstrap.min.css' %}">
    <style>
    .navbar {
    border-radius: 0px;
    }
    </style>
    </head>
    <body>

    <nav class="navbar navbar-default">
    <div class="container-fluid">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
    data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
    <span class="sr-only">Toggle navigation</span>
    <span class="icon-bar"></span>
    <span class="icon-bar"></span>
    <span class="icon-bar"></span>
    </button>
    <a class="navbar-brand" href="#">用户管理系统</a>
    </div>


    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
    <ul class="nav navbar-nav">
    <li><a href="/depart/list/">部门管理</a></li>
    <li><a href="#">用户管理</a></li>

    </ul>
    <ul class="nav navbar-nav navbar-right">
    <li><a href="#">登录</a></li>

    <li class="dropdown">
    <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
    aria-expanded="false">我的 <span class="caret"></span></a>
    <ul class="dropdown-menu">
    <li><a href="#">个人资料</a></li>
    <li><a href="#">我的信息</a></li>
    <li role="separator" class="divider"></li>
    <li><a href="#">注销</a></li>
    </ul>
    </li>
    </ul>
    </div>
    </div>
    </nav>

    <div>
    {% block content %}{% endblock %}
    </div>


    <script src="{% static 'js/jquery-3.6.1.min.js' %}"></script>
    <script src="{% static 'plugins/bootstrap3/js/bootstrap.min.js' %}"></script>
    </body>
    </html>
  • depart_list.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    {% extends 'layoyt.html' %}

    {% block content %}
    <div class="container">
    <div style="margin-bottom: 10px">
    <a class="btn btn-success" href="/depart/add/">
    <span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
    新建部门
    </a>
    </div>

    <div class="panel panel-default">
    <!-- Default panel contents -->
    <div class="panel-heading">
    <span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
    部门列表
    </div>

    <!-- Table -->
    <table class="table table-bordered">
    <thead>
    <tr>
    <th>ID</th>
    <th>名称</th>
    <th>操作</th>
    </tr>
    </thead>
    <tbody>
    {% for obj in querysite %}
    <tr>
    <th>{{ obj.id }}</th>
    <td>{{ obj.title }}</td>
    <td>
    <a class="btn btn-primary btn-xs" href="/depart/{{ obj.id }}/edit/">编辑</a>
    <a class="btn btn-danger btn-xs" href="/depart/delete/?nid={{ obj.id }}">删除</a>
    </td>
    </tr>
    {% endfor %}
    </tbody>
    </table>
    </div>

    </div>
    {% endblock %}


  • depart_add.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    {% extends 'layoyt.html' %}

    {% block content %}
    <div class="container">
    <div class="panel panel-default">
    <div class="panel-heading">
    <h3 class="panel-title">新建部门</h3>
    </div>
    <div class="panel-body">
    <form method="post">
    {% csrf_token %}
    <div class="form-group">
    <label>标题</label>
    <input type="text" class="form-control" placeholder="标题" name="title">
    </div>
    <button type="submit" class="btn btn-primary">提 交</button>
    </form>
    </div>
    </div>
    </div>
    {% endblock %}

  • depart_edit.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    {% extends 'layoyt.html' %}

    {% block content %}
    <div class="container">
    <div class="panel panel-default">
    <div class="panel-heading">
    <h3 class="panel-title">修改部门</h3>
    </div>
    <div class="panel-body">
    <form method="post">
    {% csrf_token %}
    <div class="form-group">
    <label>标题</label>
    <input type="text" class="form-control" placeholder="标题" name="title" value="{{ row_object.title }}">
    </div>
    <button type="submit" class="btn btn-primary">提 交</button>
    </form>
    </div>
    </div>
    </div>
    {% endblock %}

用户管理

  • 先手动输入一些数据
    1
    2
    3
    insert into  app01_userinfo(
    name,password,age,account,create_time,gender,depart_id)
    values("zhang","123",20,10000000,"2022-9-1",1,1);

添加用户

原始方法

问题:
1.用户提交数据没有校验
2.页面输入错误应该有提示
3.错误后,页面每一个数据都需要重新写
4.关联的数据需要手动获取循环展示到页面

  • Django组件
    • Form组件
      可以帮助我们解决前三个问题
    • ModelForm组件

初识Form

  1. view.py
  • 自动生成input框
    1
    2
    3
    4
    5
    6
    7
    8
    class MyForm(Form):
    user = forms.CharFiled(widght=forms.Input)
    pwd = forms.CharFiled(widght=forms.Input)

    def user_add(request):
    """添加用户(原始方法)"""
    if request.method == "GET":
    return render(request, 'user_add.html',{"form":form})
  1. user_add.html
  • 循环写
    1
    2
    3
    4
    5
    <form method="post">
    {% for field in form %}
    {{ field }}
    {% endfor %}
    </form>
  • 逐一写
    1
    2
    3
    4
    <form method="post">
    {{ form.user }}
    {{ form.pwd }}
    </form>

ModelForm(推荐)

  1. models.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class UserInfo(models.Model):
    """员工表"""
    name = models.CharField(verbose_name="姓名", max_length=16)
    password = models.CharField(verbose_name="密码", max_length=64)
    age = models.IntegerField(verbose_name="年龄")
    account = models.DecimalField(verbose_name="账户余额", max_digits=10, decimal_places=2, default=0)
    create_time = models.DateTimeField(verbose_name="入职时间")
    depart = models.ForeignKey(to="Department", to_field="id", on_delete=models.CASCADE)
    gender_choices = (
    (1, "男"),
    (2, "女")
    )
    gender = models.SmallIntegerField(verbose_name="性别", choices=gender_choices)
  2. view.py
  • 自动生成input框(可以自定义,也可以直接去拿)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class MyForm(ModelForm):
    user = forms.CharFiled(widght=forms.Input)
    class Mete:
    model = UserInfo
    field = ["name","user","password","age"]

    def user_add(request):
    """添加用户(原始方法)"""
    if request.method == "GET":
    return render(request, 'user_add.html',{"form":form})
  • 设置settings.py 将默认文字为中文

员工管理系统(用户管理)

  • user_model_form_add.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{% extends 'layoyt.html' %}

{% block content %}
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">新建用户</h3>
</div>
<div class="panel-body">
<form method="post" novalidate>
{% csrf_token %}

{% for field in form %}
<div class="form-group">
<label>{{ field.label }}</label>
{{ field }}
<span style="color: red">
{{ field.errors.0 }}
</span>
</div>
{% endfor %}

<button type="submit" class="btn btn-primary">提 交</button>
</form>
</div>
</div>
</div>
{% endblock %}
  • views.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    def user_model_form_add(request):
    """基于modelform的添加用户"""
    if request.method == "GET":
    form = UserModelForm
    return render(request,'user_model_form_add.html', {"form": form})

    # 用户POST提交数据,数据校验
    form = UserModelForm(data=request.POST)
    if form.is_valid():
    # 数据合法,保存到数据库
    # models.UserInfo.objects.create()
    form.save()
    return redirect("/user/list/")
    else:
    return render(request,'user_model_form_add.html', {"form": form})

    补充编辑删除以后的代码

  • 编辑用户
    • 点击编辑,跳转到编辑页面(将编辑行的id携带过去)
    • 错误校验
    • 数据库更新
  • 删除用户
  1. views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def user_edit(request, nid):
"""编辑页面"""
if request.method == "GET":
# 根据id获取要编辑的那一行数据
row_object = models.UserInfo.objects.filter(id=nid).first()
form = UserModelForm(instance=row_object)
return render(request, 'user_edit.html', {'form':form})

row_object = models.UserInfo.objects.filter(id=nid).first()
form = UserModelForm(data=request.POST, instance=row_object)
if form.is_valid():
# 默认保存的是用户输入的数据
form.save()
return redirect('/user/list/')
return render(request, 'user_edit.html', {"form": form})

def user_delete(request, nid):
models.UserInfo.objects.filter(id=nid).first().delete()
return redirect('/user/list')
  1. user_model_form_edit.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    {% extends 'layoyt.html' %}

    {% block content %}
    <div class="container">
    <div class="panel panel-default">
    <div class="panel-heading">
    <h3 class="panel-title">编辑用户</h3>
    </div>
    <div class="panel-body">
    <form method="post" novalidate>
    {% csrf_token %}

    {% for field in form %}
    <div class="form-group">
    <label>{{ field.label }}</label>
    {{ field }}
    <span style="color: red">
    {{ field.errors.0 }}
    </span>

    </div>
    {% endfor %}

    <button type="submit" class="btn btn-primary">提 交</button>
    </form>
    </div>
    </div>
    </div>
    {% endblock %}
  2. 其它修改

号码管理

表结构

  • 设计表
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    class PrettyNum(models.Model):
    """靓号表"""
    mobile = models.CharField(verbose_name="手机号", max_length=11)
    price = models.IntegerField(verbose_name="价格", default=0)

    level_choices = (
    (1, "1级"),
    (2, "2级"),
    (3, "3级"),
    (4, "4级"),
    )
    level = models.SmallIntegerField(verbose_name="级别", choices=level_choices, default=1)

    status_choices = (
    (1, "已占用"),
    (2, "未使用"),
    )
    status = models.SmallIntegerField(verbose_name="状态", choices=status_choices, default=2)
  • 命令创建表

号码列表

  • URL
  • 函数
    • 获取所有的靓号
    • 结合HTML+render将靓号罗列出来
1
2
3
def pretty_list(request):
queryset = models.PrettyNum.objects.all().order_by("-level")
return render(request, 'pretty_list.html', {"queryset": queryset})
  • pretty_list.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    {% extends 'layoyt.html' %}

    {% block content %}
    <div class="container">
    <div style="margin-bottom: 10px" class="clearfix">
    <a class="btn btn-success" href="/pretty/add/">
    <span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
    新建靓号
    </a>

    <div style="float: right; width: 300px;">
    <form method="get">
    <div class="input-group">
    <input type="text" name="q" class="form-control" placeholder="Search for..."
    value="{{ search_data }}">
    <span class="input-group-btn">
    <button class="btn btn-default" type="submit">
    <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
    </button>
    </span>
    </div><!-- /input-group -->
    </form>
    </div>

    <div class="panel panel-default">
    <!-- Default panel contents -->
    <div class="panel-heading">
    <span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
    用户列表
    </div>

    <!-- Table -->
    <table class="table table-bordered">
    <thead>
    <tr>
    <th>ID</th>
    <th>号码</th>
    <th>价格</th>
    <th>级别</th>
    <th>状态</th>
    </tr>
    </thead>
    <tbody>
    {% for obj in queryset %}
    <tr>
    <th>{{ obj.id }}</th>
    <td>{{ obj.mobile }}</td>
    <td>{{ obj.price }}</td>
    <td>{{ obj.get_level_display }}</td>
    <td>{{ obj.get_status_display }}</td>
    <td>
    <a class="btn btn-primary btn-xs" href="/pretty/{{ obj.id }}/edit/">编辑</a>
    <a class="btn btn-danger btn-xs" href="/pretty/{{ obj.id }}/delete/">删除</a>
    </td>
    </tr>
    {% endfor %}
    </tbody>
    </table>
    </div>
    </div>
    </div>
    {% endblock %}

新建号码

  • 列表页面点击跳转:/pretty/add/
  • URL
  • 函数
  • ModelForm的类
  • 函数
    • 实例化类的对象
    • 通过render将对象传入HTML中
    • 模板的循环展示所有的字段
  • 点击提交
    • 数据校验
    • 保存到数据库
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      class PrettyModelForm(forms.ModelForm):
      # 验证:方式一
      # 通过正则表达式规范校验手机号码
      mobile = forms.CharField(
      label="手机号",
      validators=[RegexValidator(r'^1\d{8}', "号码格式错误")]
      )

      class Meta:
      model = models.PrettyNum
      # fields = "__all__"
      fields = ["mobile", "price", "level", "status"]

      def __init__(self, *args, **kwargs):
      super().__init__(*args, **kwargs)
      for name, field in self.fields.items():
      field.widget.attrs = {"class": "form-control"}

      # 验证:方式二
      def clean_mobile(self):
      txt_mobile = self.cleaned_data["mobile"]

      exits = models.PrettyNum.objects.filter(mobile=txt_mobile).exists()
      if exits:
      raise ValidationError("手机号已存在")
      return txt_mobile


      def pretty_add(request):
      """添加靓号"""
      if request.method == "GET":
      form = PrettyModelForm()
      return render(request, 'pretty_add.html', {"form": form})
      form = PrettyModelForm(data=request.POST)
      if form.is_valid():
      form.save()
      return redirect("/pretty/list/")
      else:
      return render(request, 'pretty_add.html', {"form": form})
  • pretty_add.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    {% extends 'layoyt.html' %}

    {% block content %}
    <div class="container">
    <div class="panel panel-default">
    <div class="panel-heading">
    <h3 class="panel-title">新建靓号</h3>
    </div>
    <div class="panel-body">
    <form method="post" novalidate>
    {% csrf_token %}

    {% for field in form %}
    <div class="form-group">
    <label>{{ field.label }}</label>
    {{ field }}
    <span style="color: red">
    {{ field.errors.0 }}
    </span>

    </div>
    {% endfor %}

    <button type="submit" class="btn btn-primary">提 交</button>
    </form>
    </div>
    </div>
    </div>
    {% endblock %}

    编辑号码

  • 列表页面点击跳转:/pretty/edit/
  • URL
  • 函数
    • 根据id获取当前编辑的对象
    • ModelForm配合,默认显示数据
    • 提交修改

不允许靓号重复

  • 添加(正则表达式)
  • 编辑(正则表达式)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class PrettyEditModelForm(forms.ModelForm):
# mobile = forms.CharField(disabled=True,label="手机号")
class Meta:
model = models.PrettyNum
# fields = "__all__"
fields = ["mobile", "price", "level", "status"]

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
field.widget.attrs = {"class": "form-control"}

def clean_mobile(self):
txt_mobile = self.cleaned_data["mobile"]

exits = models.PrettyNum.objects.exclude(id=self.instance.pk).filter(mobile=txt_mobile).exists()
if exits:
raise ValidationError("手机号已存在")
return txt_mobile


def pretty_edit(request, nid):
"""编辑靓号"""
row_object = models.PrettyNum.objects.filter(id=nid).first()
if request.method == "GET":
form = PrettyEditModelForm(instance=row_object)
return render(request, 'pretty_edit.html', {"form": form})
form = PrettyEditModelForm(instance=row_object, data=request.POST)
if form.is_valid():
form.save()
return redirect("/pretty/list/")
else:
return render(request, 'pretty_edit.html', {"form": form})
  • pretty_edit.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    {% extends 'layoyt.html' %}

    {% block content %}
    <div class="container">
    <div class="panel panel-default">
    <div class="panel-heading">
    <h3 class="panel-title">编辑靓号</h3>
    </div>
    <div class="panel-body">
    <form method="post" novalidate>
    {% csrf_token %}

    {% for field in form %}
    <div class="form-group">
    <label>{{ field.label }}</label>
    {{ field }}
    <span style="color: red">
    {{ field.errors.0 }}
    </span>

    </div>
    {% endfor %}

    <button type="submit" class="btn btn-primary">提 交</button>
    </form>
    </div>
    </div>
    </div>
    {% endblock %}

    删除号码

    1
    2
    3
    def pretty_delete(request, nid):
    models.PrettyNum.objects.filter(id=nid).delete()
    return redirect('/pretty/list')

分页和分页组件

分页(一般写法)

  • views.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    def pretty_list(request):
    """靓号列表"""
    data_dict = {}
    search_data = request.GET.get('q', "")
    if search_data:
    data_dict['mobile__contains'] = search_data

    page = int(request.GET.get('page', 1))
    page_size = 10
    start = (page - 1) * page_size
    end = page * page_size
    # 数据总条数
    total_count = models.PrettyNum.objects.filter(**data_dict).order_by("-level").count()
    queryset = models.PrettyNum.objects.filter(**data_dict).order_by("-level")[start:end]

    # 总页码
    total_page_count, div = divmod(total_count, page_size)
    if div:
    total_page_count += 1

    # 计算出当前页得到前五页和后五页
    plus = 5
    if total_page_count <= 2 * plus + 1:
    start_page = 1
    end_page = total_page_count + 1
    else:
    # 数据库数据比较多 > 11 页

    if page <= plus:
    start_page = 1
    end_page = 2 * plus + 1
    else:
    if (page + plus) > total_page_count:
    start_page = total_page_count - 2 * plus
    end_page = total_page_count
    else:
    start_page = page - plus
    end_page = page + plus + 1
    # 页码
    page_str_list = []

    page_str_list.append('<li><a href="?page={}">首页</a></li>'.format(1))

    # 上一页
    if page > 1:
    prev = '<li><a href="?page={}">上一页</a></li>'.format(page - 1)
    else:
    prev = '<li><a href="?page={}">上一页</a></li>'.format(1)
    page_str_list.append(prev)

    for i in range(start_page, end_page):
    if i == page:
    ele = '<li class="active"><a href="?page={}">{}</a></li>'.format(i, i)
    else:
    ele = '<li><a href="?page={}">{}</a></li>'.format(i, i)
    page_str_list.append(ele)

    # 下一页
    if page < total_page_count:
    prev = '<li><a href="?page={}">下一页</a></li>'.format(page + 1)
    else:
    prev = '<li><a href="?page={}">下一页</a></li>'.format(total_page_count)
    page_str_list.append(prev)

    # 尾页
    page_str_list.append('<li><a href="?page={}">尾页</a></li>'.format(total_page_count))

    search_string = """
    <li>
    <form style="float: left; margin-left: -1px" method="get">
    <div class="input-group" style="width: 200px" >
    <input type="text" name="page" class="form-control" placeholder="页数">
    <span class="input-group-btn">
    <button class="btn btn-default" type="submit">跳转</button>
    </span>
    </div>
    </form>
    </li>
    """
    page_str_list.append(search_string)

    page_string = mark_safe("".join(page_str_list))

    return render(request, 'pretty_list.html',
    {"queryset": queryset, "search_data": search_data, "page_string": page_string}, )
  • pretty_list

  • 效果展示

分页组件的封装

  • 新建文件

pagination公共组件

  • pagination
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
"""
自定义的分页组件,以后如果想要使用分页组件

在视图函数中
def pretty_list(request):

# 根据自己的情况去筛选自己的数据
queryset = models.PrettyNum.objects.all()

# 实例化分页对象
page_object = Pagination(request, queryset)

context = {
"search_data": search_data,
"queryset": page_object.page_queryset, # 分完页的数据
"page_string": page_object.html() # 页码
}

return render(request, 'pretty_list.html', context)

在HTML页面中

{% for obj in queryset %}
{{ obj.xx }}
{% endfor %}



<ul class="pagination">
{{ page_string }}
</ul>
"""

from django.utils.safestring import mark_safe


class Pagination(object):
def __init__(self, request, queryset, page_size=10, page_param="page", plus=5):
"""
:param request: 请求的对象
:param queryset: 查询的符合条件的数据(根据这个数据进行处理)
:param page_size: 每页显示多少条数据
:param page_param: 在URL中传递的参数
:param plus: 显示当前页的前或后几页
"""
page = request.GET.get(page_param, "1")
if page.isdecimal():
page = int(page)
else:
page = 1

self.page = page
self.page_size = page_size

self.start = (page - 1) * page_size
self.end = page * page_size

self.page_queryset = queryset[self.start:self.end]

total_count = queryset.count()
total_page_count, div = divmod(total_count, page_size)
if div:
total_page_count += 1
self.total_page_count = total_page_count
self.plus = plus


def html(self):
# 计算出当前页得到前五页和后五页
if self.total_page_count <= 2 * self.plus + 1:
start_page = 1
end_page = self.total_page_count + 1
else:
# 数据库数据比较多 > 11 页

if self.page <= self.plus:
start_page = 1
end_page = 2 * self.plus + 1
else:
if (self.page + self.plus) > self.total_page_count:
start_page = self.total_page_count - 2 * self.plus
end_page = self.total_page_count
else:
start_page = self.page - self.plus
end_page = self.page + self.plus + 1
# 页码
page_str_list = []

page_str_list.append('<li><a href="?page={}">首页</a></li>'.format(1))

# 上一页
if self.page > 1:
prev = '<li><a href="?page={}">上一页</a></li>'.format(self.page - 1)
else:
prev = '<li><a href="?page={}">上一页</a></li>'.format(1)
page_str_list.append(prev)

for i in range(start_page, end_page):
if i == self.page:
ele = '<li class="active"><a href="?page={}">{}</a></li>'.format(i, i)
else:
ele = '<li><a href="?page={}">{}</a></li>'.format(i, i)
page_str_list.append(ele)

# 下一页
if self.page < self.total_page_count:
prev = '<li><a href="?page={}">下一页</a></li>'.format(self.page + 1)
else:
prev = '<li><a href="?page={}">下一页</a></li>'.format(self.total_page_count)
page_str_list.append(prev)

# 尾页
page_str_list.append('<li><a href="?page={}">尾页</a></li>'.format(self.total_page_count))

search_string = """
<li>
<form style="float: left; margin-left: -1px" method="get">
<div class="input-group" style="width: 200px" >
<input type="text" name="page" class="form-control" placeholder="页数">
<span class="input-group-btn">
<button class="btn btn-default" type="submit">跳转</button>
</span>
</div>
</form>
</li>
"""
page_str_list.append(search_string)

page_string = mark_safe("".join(page_str_list))

return page_string

bug

  • 在搜索下分页查询不保留搜索条件

在分页的时候,保留搜索条件

  • pagination.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    """
    自定义的分页组件,以后如果想要使用分页组件

    在视图函数中
    def pretty_list(request):

    # 根据自己的情况去筛选自己的数据
    queryset = models.PrettyNum.objects.all()

    # 实例化分页对象
    page_object = Pagination(request, queryset)

    context = {
    "search_data": search_data,
    "queryset": page_object.page_queryset, # 分完页的数据
    "page_string": page_object.html() # 页码
    }

    return render(request, 'pretty_list.html', context)

    在HTML页面中

    {% for obj in queryset %}
    {{ obj.xx }}
    {% endfor %}



    <ul class="pagination">
    {{ page_string }}
    </ul>
    """

    from django.utils.safestring import mark_safe
    import copy

    class Pagination(object):
    def __init__(self, request, queryset, page_size=10, page_param="page", plus=5):
    """
    :param request: 请求的对象
    :param queryset: 查询的符合条件的数据(根据这个数据进行处理)
    :param page_size: 每页显示多少条数据
    :param page_param: 在URL中传递的参数
    :param plus: 显示当前页的前或后几页
    """

    query_dict = copy.deepcopy(request.GET)
    query_dict._mutable = True
    self.query_dict = query_dict

    self.page_param = page_param
    page = request.GET.get(page_param, "1")
    if page.isdecimal():
    page = int(page)
    else:
    page = 1

    self.page = page
    self.page_size = page_size

    self.start = (page - 1) * page_size
    self.end = page * page_size

    self.page_queryset = queryset[self.start:self.end]

    total_count = queryset.count()
    total_page_count, div = divmod(total_count, page_size)
    if div:
    total_page_count += 1
    self.total_page_count = total_page_count
    self.plus = plus


    def html(self):
    # 计算出当前页得到前五页和后五页
    if self.total_page_count <= 2 * self.plus + 1:
    start_page = 1
    end_page = self.total_page_count + 1
    else:
    # 数据库数据比较多 > 11 页

    if self.page <= self.plus:
    start_page = 1
    end_page = 2 * self.plus + 1
    else:
    if (self.page + self.plus) > self.total_page_count:
    start_page = self.total_page_count - 2 * self.plus
    end_page = self.total_page_count
    else:
    start_page = self.page - self.plus
    end_page = self.page + self.plus + 1
    # 页码
    page_str_list = []

    self.query_dict.setlist(self.page_param,[1])
    page_str_list.append('<li><a href="?{}">首页</a></li>'.format(self.query_dict.urlencode()))

    # 上一页
    if self.page > 1:
    self.query_dict.setlist(self.page_param, [self.page - 1])
    prev = '<li><a href="?{}">上一页</a></li>'.format(self.query_dict.urlencode())
    else:
    self.query_dict.setlist(self.page_param, [1])
    prev = '<li><a href="?{}">上一页</a></li>'.format(self.query_dict.urlencode())
    page_str_list.append(prev)

    for i in range(start_page, end_page):
    self.query_dict.setlist(self.page_param, [i])
    if i == self.page:
    ele = '<li class="active"><a href="?{}">{}</a></li>'.format(self.query_dict.urlencode(), i)
    else:
    ele = '<li><a href="?{}">{}</a></li>'.format(self.query_dict.urlencode(), i)
    page_str_list.append(ele)

    # 下一页
    if self.page < self.total_page_count:
    self.query_dict.setlist(self.page_param, [self.page + 1])
    self.query_dict.urlencode()
    prev = '<li><a href="?{}">下一页</a></li>'.format(self.query_dict.urlencode())
    else:
    self.query_dict.setlist(self.page_param, [self.total_page_count])
    prev = '<li><a href="?{}">下一页</a></li>'.format(self.query_dict.urlencode())
    page_str_list.append(prev)

    # 尾页
    self.query_dict.setlist(self.page_param, [self.total_page_count])
    page_str_list.append('<li><a href="?{}">尾页</a></li>'.format(self.query_dict.urlencode()))

    search_string = """
    <li>
    <form style="float: left; margin-left: -1px" method="get">
    <div class="input-group" style="width: 200px" >
    <input type="text" name="page" class="form-control" placeholder="页数">
    <span class="input-group-btn">
    <button class="btn btn-default" type="submit">跳转</button>
    </span>
    </div>
    </form>
    </li>
    """
    page_str_list.append(search_string)

    page_string = mark_safe("".join(page_str_list))

    return page_string

使用

  • 放在任意py文件中,在用的文件中进行导入
  • 具体操作说明

管理员操作

文件目录结构

  • urls.py
  • admin.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    from django.shortcuts import render, redirect

    from app01 import models
    from app01.utils.pagiantion import Pagination


    def admin_list(request):
    """管理员列表"""
    # 搜索
    data_dict = {}
    search_data = request.GET.get('q', "")
    if search_data:
    data_dict['username__contains'] = search_data

    queryset = models.Admin.objects.filter(**data_dict)

    # 分页
    page_object = Pagination(request, queryset)
    context = {
    "queryset": page_object.page_queryset,
    "page_string": page_object.html(),
    "search_data": search_data,
    }

    return render(request, "admin_list.html", context)


    from django import forms
    from django.core.exceptions import ValidationError
    from app01.utils.bootstrap import BootStrapModelForm
    from app01.utils.encrtpt import md5


    class AdminModelForm(BootStrapModelForm):
    confirm_password = forms.CharField(
    label="确认密码",
    widget=forms.PasswordInput(render_value=True)
    )

    class Meta:
    model = models.Admin
    fields = ['username', 'password', "confirm_password"]
    widgets = {
    "password": forms.PasswordInput(render_value=True)
    }

    def clean_password(self):
    pwd = self.cleaned_data.get("password")
    return md5(pwd)

    def clean_confirm_password(self):
    pwd = self.cleaned_data.get("password")
    confirm = md5(self.cleaned_data.get("confirm_password"))
    if confirm != pwd:
    raise ValidationError("密码不一致")
    return confirm


    class AdminEditModelForm(BootStrapModelForm):
    class Meta:
    model = models.Admin
    fields = ['username']


    class AdminResetModelForm(BootStrapModelForm):
    confirm_password = forms.CharField(
    label="确认密码",
    widget=forms.PasswordInput(render_value=True)
    )

    class Meta:
    model = models.Admin
    fields = ['password' , 'confirm_password']

    def clean_password(self):
    pwd = self.cleaned_data.get("password")
    md5_pwd = md5(pwd)

    # 去数据库校验当前密码和数据库是否一致
    exists = models.Admin.objects.filter(id=self.instance.pk, password=md5_pwd).exists()
    if exists:
    raise ValidationError("密码不能与以前的相同")
    return md5(pwd)

    def clean_confirm_password(self):
    pwd = self.cleaned_data.get("password")
    confirm = md5(self.cleaned_data.get("confirm_password"))
    if confirm != pwd:
    raise ValidationError("密码不一致")
    return confirm


    def admin_add(request):
    """添加管理员"""
    title = "新建管理员"
    if request.method == "GET":
    form = AdminModelForm()
    return render(request, 'change.html', {"form": form, "title": title})

    form = AdminModelForm(data=request.POST)
    if form.is_valid():
    form.save()
    return redirect('/admin/list')

    return render(request, 'change.html', {"form": form, "title": title})


    def admin_edit(request, nid):
    """编辑管理员"""
    row_object = models.Admin.objects.filter(id=nid).first()
    if not row_object:
    # return render(request, 'error.html', {"msg": "数据不存在"})
    return redirect('/admin/list/')

    title = "编辑管理员"

    if request.method == "GET":
    form = AdminEditModelForm(instance=row_object)
    return render(request, 'change.html', {"form": form, "title": title})

    form = AdminEditModelForm(data=request.POST, instance=row_object)
    if form.is_valid():
    form.save()
    return redirect('/admin/list/')
    return render(request, 'change.html', {"form": form, "title": title})


    def admin_delete(request, nid):
    """删除管理员"""
    models.Admin.objects.filter(id=nid).delete()
    return redirect('/admin/list/')


    def admin_reset(request, nid):
    """重置密码"""
    row_object = models.Admin.objects.filter(id=nid).first()
    if not row_object:
    return redirect('/admin/list/')

    title = "重置密码-{}".format(row_object.username)

    if request.method == "GET":
    form = AdminResetModelForm()
    return render(request, 'change.html', {"form": form ,"title": title})
    form = AdminResetModelForm(data=request.POST, instance=row_object)
    if form.is_valid():
    form.save()
    return redirect('/admin/list/')
    return render(request, 'change.html', {"form": form, "title": title})
  • admin_list.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    {% extends 'layoyt.html' %}

    {% block content %}
    <div class="container">
    <div style="margin-bottom: 10px" class="clearfix">
    <a class="btn btn-success" href="/admin/add/">
    <span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
    新建管理员
    </a>

    <div style="float: right; width: 300px;">
    <form method="get">
    <div class="input-group">
    <input type="text" name="q" class="form-control" placeholder="关键字"
    value="{{ search_data }}">
    <span class="input-group-btn">
    <button class="btn btn-default" type="submit">
    <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
    </button>
    </span>
    </div><!-- /input-group -->
    </form>
    </div>

    <div class="panel panel-default">
    <!-- Default panel contents -->
    <div class="panel-heading">
    <span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
    管理员列表
    </div>

    <!-- Table -->
    <table class="table table-bordered">
    <thead>
    <tr>
    <th>ID</th>
    <th>用户名</th>
    <th>密码</th>
    <th>重置密码</th>
    <th>操作</th>
    </tr>
    </thead>
    <tbody>
    {% for obj in queryset %}
    <tr>
    <th>{{ obj.id }}</th>
    <td>{{ obj.username}}</td>
    <td>********</td>
    <td>
    <a href="/admin/{{ obj.id }}/reset/">重置密码</a>
    </td>
    <td>
    <a class="btn btn-primary btn-xs" href="/admin/{{ obj.id }}/edit/">编辑</a>
    <a class="btn btn-danger btn-xs" href="/admin/{{ obj.id }}/delete/">删除</a>
    </td>
    </tr>
    {% endfor %}
    </tbody>
    </table>
    </div>

    <div>
    <ul class="pagination">
    {{ page_string }}
    </ul>
    </div>

    </div>
    </div>
    {% endblock %}
  • change.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    {% extends 'layoyt.html' %}

    {% block content %}
    <div class="container">
    <div class="panel panel-default">
    <div class="panel-heading">
    <h3 class="panel-title">{{ title }}</h3>
    </div>
    <div class="panel-body">
    <form method="post" novalidate>
    {% csrf_token %}

    {% for field in form %}
    <div class="form-group">
    <label>{{ field.label }}</label>
    {{ field }}
    <span style="color: red">
    {{ field.errors.0 }}
    </span>

    </div>
    {% endfor %}

    <button type="submit" class="btn btn-primary">提 交</button>
    </form>
    </div>
    </div>
    </div>
    {% endblock %}
  • error.html

    1
    2
    3
    4
    5
    6
    7
    8
    {% extends 'layoyt.html' %}

    {% block content %}
    <div class="container">
    <div class="alert alert-danger" role="alert">{{ msg }}</div>
    </div>

    {% endblock %}

用户登录

1
2
http://127.0.0.1:8000/user/list/
https://127.0.0.1:8000/user/list/
  • 无状态&短链接
    一次请求一次响应(每次默认为新请求,不携带以前的状态)

  • cookie和session
    cookie:保存在浏览器上的键值对,发送请求时,自动携带
    session:服务端存储我们信息的地方
    发起请求后,网站可以在浏览器上写一个键值对,会给你一个响应体(页面),还有一个响应头(cookie),会生成一个专属的凭证。

登录界面

  • login.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    {% load static %}

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>用户登录</title>
    <link rel="stylesheet" href="{% static 'plugins/bootstrap3/css/bootstrap.min.css' %}">

    <style>

    .acount {
    width: 400px;
    border: 1px solid #ddd;
    box-shadow: 5px 5px 5px #aaa;


    margin-left: auto;
    margin-right: auto;
    margin-top: 100px;

    padding: 20px 30px;
    }

    .acount h1 {
    text-align: center;
    }

    </style>

    </head>
    <body>

    <div class="acount">
    <h2>用户登录</h2>

    <form method="post" novalidate>
    {% csrf_token %}
    <div class="form-group" >
    <label>用户名</label>
    {{ form.username }}
    <span style="color: red">{{ form.username.errors.0 }}</span>
    </div>
    <div class="form-group">
    <label>密码</label>
    {{ form.password }}
    <span style="color: red">{{ form.username.errors.0 }}</span>
    </div>


    <button type="submit" class="btn btn-primary">登录</button>
    </form>

    </div>

    </body>
    </html>
  • account.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    from django.shortcuts import render, redirect, HttpResponse
    from django import forms

    from app01 import models
    from app01.utils.bootstrap import BootStrapForm
    from app01.utils.encrtpt import md5


    class LoginForm(BootStrapForm):
    username = forms.CharField(
    label="用户名",
    widget=forms.TextInput,
    required=True
    )
    password = forms.CharField(
    label="密码",
    widget=forms.TextInput,
    required=True
    )

    def clean_password(self):
    pwd = self.cleaned_data.get("password")
    return md5(pwd)


    def login(request):
    """登录"""
    if request.method == "GET":
    form = LoginForm()
    return render(request, 'login.html', {'form': form})

    form = LoginForm(data=request.POST)
    if form.is_valid():
    # 验证成功后,获取到的用户名和密码,去数据校验(前提字典的键值和数据库一致)
    admin_object = models.Admin.objects.filter(**form.cleaned_data).first()
    if not admin_object:
    form.add_error("username", "用户名或密码错误")
    return render(request, 'login.html', {'form': form})
    # 验证通过后
    # 网站生成随机字符串,写到用户浏览器的cookie中:再写入到session中
    request.session["info"] = {'id': admin_object.id, 'name': admin_object.username}
    return redirect("/admin/list")
    return render(request, 'login.html', {'form': form})

    用户验证

    登录成功后:

  • cookie:随机字符串

  • session:用户信息
    在其他需要登录才能访问的页面中都需要加入:

    1
    2
    3
    4
    5
    6
    def admin_list(request):
    # 检查用户是否已经登录,已登录,继续,未登录,跳转至登录界面
    # 用户发来的请求,获取cookie随机字符串,拿着字符串看看session有没有
    info = request.session.get("info")
    if not info:
    return redirect('/login/')

    需要在18个页面都加入,过于繁琐,此时可使用django的中间件

    中间件

  • 请求进入网站会通过中间件,出去也会通过中间件(中间件其实就相当一个类)

  • 当中间件阻拦请求后,就会从中间件返回,用户就无法访问到视图函数

中间件的使用

  • 定义中间件
    • 写一个类
  • 使用中间件
    • settings.py中注册中间件

在中间件中没有返回值继续走,如果有返回值则继续向后走

注销

Ajax请求

浏览器向网站发送请求时候:URL和表单的形式提交

  • GET
  • POST
    特点:页面会刷新。
    除此之外,也可以基于Ajax向后台发请求(页面不会做刷新)
  • 依赖jQuery
  • 编写Ajax代码

get请求

1
2
3
4
5
6
7
8
9
10
11
12
$.ajax(
url:"发送的地址",
type:"get
",
data:{
n1:123,
n2:456,
}
sucess:function(res){
console.log(res);
}
)
1
2
3
4
5
from django.shortcuts import render, HttpResponse

def task_ajak(request):
print(request.GET)
return HttpResponse("成功了")

post请求

1
2
3
4
5
6
7
8
9
10
11
$.ajax(
url:"发送的地址",
type:"post",
data:{
n1:123,
n2:456,
}
sucess:function(res){
console.log(res);
}
)

对于post请求需要携带session,这个过程过于繁琐,可以采用免除csrf_token认证

1
2
3
4
5
6
7
8
from django.shortcuts import render, HttpResponse
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def task_ajax(request):
print(request.GET)
print(request.POST)
return HttpResponse("成功了")

关于绑定事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{% extends 'layoyt.html' %}

{% block content %}
<div class="container">
<h1>任务管理</h1>

<h3>示例1</h3>
<input id="btn1" type="button" class="btn btn-primary" value="点击">
</div>

{% endblock %}

{% block js %}
<script type="text/javascript">
$(function () {
//页面加载完成之后代码自动执行
bindBtn1Event();
})

function bindBtn1Event(){
$("#btn1").click(function (){
$.ajax({
url: '/task/ajax/',
type: "post",
data: {
n1: 123,
n2: 456
},
success: function (res){
console.log(res)
}
})
})
}

</script>
{% endblock %}

ajax请求的返回值

返回的是json格式

案例:表单

  • task_list.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    {% extends 'layoyt.html' %}

    {% block content %}
    <div class="container">
    <div class="panel panel-default">
    <div class="panel-heading">表单</div>
    <div class="panel-body">
    <form id="formAdd">
    <div class="clearfix">
    {% for field in form %}
    <div class="form-group col-xs-6" style="position: relative;margin-bottom: 20px">
    <label>{{ field.label }}</label>
    {{ field }}
    <span class="error-msg" style="color: red;position: absolute"></span>
    </div>
    {% endfor %}
    <div class="col-xs-12">
    <button id="btnAdd" type="button" class="btn btn-primary">提 交</button>
    </div>
    </div>
    </form>

    </div>
    </div>
    </div>

    {% endblock %}

    {% block js %}
    <script type="text/javascript">
    $(function () {
    //页面加载完成之后代码自动执行
    bindBtnAddEvent();
    })

    function bindBtnAddEvent() {
    $("#btnAdd").click(function () {
    $(".error-msg").empty();
    $.ajax({
    url: '/task/add/',
    type: "post",
    data: $("#formAdd").serialize(),
    dataType: "JSON",
    success: function (res) {
    if(res.status){
    alert("添加成功")
    }else{
    $.each(res.error,function (name,data){
    $("#id_" + name).next().text(data[0]);
    })
    }

    }
    })
    })
    }

    </script>
    {% endblock %}
  • task.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    import json
    from django import forms
    from django.shortcuts import render, HttpResponse
    from django.http import JsonResponse
    from django.views.decorators.csrf import csrf_exempt

    from app01 import models
    from app01.utils.bootstrap import BootStrapModelForm


    class TaskModeForm(BootStrapModelForm):
    class Meta:
    model = models.Task
    fields = "__all__"
    widgets = {
    # "detail": forms.Textarea
    "detail": forms.TextInput
    }


    def task_list(request):
    """任务列表"""
    form = TaskModeForm

    return render(request, 'task_list.html' , {"form":form})


    @csrf_exempt
    def task_add(request):
    print(request.POST)
    # 1.用户发送过来的数据进行校验()
    form = TaskModeForm(data=request.POST)
    if form.is_valid():
    form.save()
    data_dict = {"status": True}
    return HttpResponse(json.dumps(data_dict))
    data_dict = {"status": False, 'error': form.errors}
    return HttpResponse(json.dumps(data_dict, ensure_ascii=False))

基于Ajax的订单管理

创建表结构

1
2
3
4
5
6
7
8
9
10
11
12
13
class Order(models.Model):
"""工单"""
oid = models.CharField(verbose_name="订单号", max_length=64)
title = models.CharField(verbose_name="名称", max_length=32)
price = models.IntegerField(verbose_name="价格")

status_choices = (
(1, "待支付"),
(2, "已支付"),
)
status = models.SmallIntegerField(verbose_name="状态", choices=status_choices, default=1)

admin = models.ForeignKey(verbose_name="管理员", to="Admin", on_delete=models.CASCADE)

前端页面

  • order_list.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    {% extends 'layoyt.html' %}

    {% block content %}
    <div class="container">
    <div>
    <input id="btnAdd" type="button" value="新建订单" class="btn btn-primary">
    </div>

    <div class="panel panel-default">
    <!-- Default panel contents -->
    <div class="panel-heading">
    <span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
    订单列表
    </div>
    <!-- Table -->
    <table class="table table-bordered">
    <thead>
    <tr>
    <th>ID</th>
    <th>订单号</th>
    <th>名称</th>
    <th>价格</th>
    <th>状态</th>
    <th>管理员</th>
    <th>操作</th>
    </tr>
    </thead>
    <tbody>
    {% for obj in queryset %}
    <tr>
    <th>{{ obj.id }}</th>
    <td>{{ obj.oid }}</td>
    <td>{{ obj.title }}</td>
    <td>{{ obj.price }}</td>
    <td>{{ obj.get_status_display }}</td>
    <td>{{ obj.admin.username }}</td>
    <td>
    <input uid="{{ obj.id }}" type="button" class="btn btn-primary btn-xs btn-edit" value="编辑">
    <input uid="{{ obj.id }}" class="btn btn-danger btn-xs btn-delete" type="button" value="删除">
    </td>
    </tr>
    {% endfor %}
    </tbody>
    </table>
    </div>
    <ul class="pagination">
    {{ page_string }}
    </ul>

    <!-- 新建/编辑 订单Modal -->
    <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
    <div class="modal-content">
    <div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
    aria-hidden="true">&times;</span></button>
    <h4 class="modal-title" id="myModalLabel">新建</h4>
    </div>
    <div class="modal-body">
    <form id="formAdd">
    <div class="clearfix">
    {% for field in form %}
    <div class="form-group col-xs-6" style="position: relative;margin-bottom: 20px">
    <label>{{ field.label }}</label>
    {{ field }}
    <span class="error-msg" style="color: red;position: absolute"></span>
    </div>
    {% endfor %}
    </div>
    </form>
    </div>
    <div class="modal-footer">
    <button type="button" class="btn btn-default" data-dismiss="modal">取 消</button>
    <button id="btnSave" type="button" class="btn btn-primary">保 存</button>
    </div>
    </div>
    </div>
    </div>

    <!-- 删除Modal -->
    <div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">

    <div class="alert alert-danger alert-dismissible fade in" role="alert">
    <h4>是否确定删除</h4>
    <p>删除后所有关联的相关数据都将会被删除。</p>
    <p style="text-align: right">
    <button id="btnConfirmDelete" type="button" class="btn btn-danger">确定</button>
    <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
    </p>
    </div>

    </div>
    </div>
    </div>
    {% endblock %}

    {% block js %}
    <script type="text/javascript">
    var DELETE_ID;
    var EDIT_ID;

    $(function () {
    bindBtnAddEvent();
    bindBtnSaveEvent();
    bindBtnDeleteEvent();
    bindBtnConfirmDelete();
    bindBtnEditDelete();
    })

    function bindBtnAddEvent() {
    $("#btnAdd").click(function () {
    // 将当前的编辑置空
    EDIT_ID = undefined;

    $("#formAdd")[0].reset();

    $('#myModalLabel').text("新建");
    //点击新建按钮,显示订单
    $('#myModal').modal('show');
    })
    }

    function bindBtnSaveEvent() {
    $("#btnSave").click(function () {
    // 清除错误信息
    $(".error-msg").empty();

    if(EDIT_ID){
    // 编辑
    doEdit();
    }else{
    // 添加
    doAdd();
    }

    })
    }

    function doEdit(){
    // 向后台发送信息(添加的ajax请求)
    $.ajax({
    url: "/order/edit/" + "?uid=" + EDIT_ID, //编辑的id
    type: "post",
    data: $("#formAdd").serialize(),
    dataType: "JSON",
    success: function (res) {
    if (res.status) {
    // 清空表单
    $("#formAdd")[0].reset();
    // 关闭对话框
    $('#myModal').modal('hide');
    location.reload();
    } else {
    if (res.tips) {
    alert(res.tips);
    } else {
    $.each(res.error, function (name, errorList) {
    $("#id_" + name).next().text(errorList[0]);
    })
    }
    }
    }
    })
    }

    function doAdd(){
    // 向后台发送信息(添加的ajax请求)
    $.ajax({
    url: '/order/add/',
    type: "post",
    data: $("#formAdd").serialize(),
    dataType: "JSON",
    success: function (res) {
    if (res.status) {
    alert("创建成功");
    $("#formAdd")[0].reset();
    $('#myModal').modal('hide');
    location.reload();
    } else {
    $.each(res.error, function (name, errorList) {
    $("#id_" + name).next().text(errorList[0]);
    })
    }
    }
    })
    }

    function bindBtnDeleteEvent() {
    $(".btn-delete").click(function () {
    // alert("确认删除");
    $('#deleteModal').modal('show');

    // 获取uid赋值给全局变量
    DELETE_ID = $(this).attr("uid");
    });
    }

    function bindBtnConfirmDelete() {
    $("#btnConfirmDelete").click(function () {
    // 点击确定删除,将DELETEID发送到后台
    $.ajax({
    url: "/order/delete/",
    type: "GET",
    data:{
    uid: DELETE_ID
    },
    dataType: "JSON",
    success: function (res){
    if (res.status) {
    alert("删除成功");
    location.reload();
    } else {
    alert(res.error);
    }
    }
    })
    })
    }

    function bindBtnEditDelete(){
    $(".btn-edit").click(function (){
    $("#formAdd")[0].reset();

    var uid = $(this).attr("uid");
    EDIT_ID = uid;

    // 发送ajax请求去后台获取数据
    $.ajax({
    url: "/order/detail/",
    type: "get",
    data: {
    uid: uid
    },
    success: function (res) {
    if (res.status) {
    // 将数据赋值
    $.each(res.data, function (name,value){
    $("#id_" + name).val(value);
    })

    // 修改对话框标题
    $('#myModalLabel').text("编辑");

    //点击编辑,显示对话框
    $('#myModal').modal('show');
    } else {
    alert(res.error);
    }
    }
    })

    // 在对话框中默认看到
    })
    }

    </script>

    {% endblock %}

    后台管理

  • order.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    import random
    from datetime import datetime
    from django.shortcuts import render
    from django.http import JsonResponse
    from django.views.decorators.csrf import csrf_exempt
    from app01.utils.bootstrap import BootStrapModelForm
    from app01 import models
    from app01.utils.pagiantion import Pagination


    class OrderModelForm(BootStrapModelForm):
    class Meta:
    model = models.Order
    # fields = "__all__"
    exclude = ["oid", "admin"]


    def order_list(request):
    """订单列表"""
    queryset = models.Order.objects.all().order_by('-id')
    page_object = Pagination(request, queryset)

    form = OrderModelForm

    context = {
    "form": form,
    "queryset": page_object.page_queryset,
    "page_string": page_object.html()
    }

    return render(request, 'order_list.html', context)


    @csrf_exempt
    def order_add(request):
    """新建订单(ajax)"""
    form = OrderModelForm(data=request.POST)
    if form.is_valid():
    # 生成订单号
    form.instance.oid = datetime.now().strftime("%Y%m%d%H%M%S") + str(random.randint(1000, 9999))
    # 固定设置管理员(当前登录系统的人的id)
    form.instance.admin_id = request.session["info"]["id"]
    # 保存到数据库
    form.save()
    return JsonResponse({"status": True})
    return JsonResponse({"status": False, "error": form.errors})


    def order_delete(requeset):
    """删除订单"""
    uid = requeset.GET.get("uid")
    exists = models.Order.objects.filter(id=uid).exists()
    if not exists:
    return JsonResponse({"status": False, 'error':"数据不存在"})
    models.Order.objects.filter(id=uid).delete()
    return JsonResponse({"status": True})


    def order_detail(requeset):
    """根据id获取订单详情"""

    # 方式一
    """
    uid = requeset.GET.get("uid")
    row_object = models.Order.objects.filter(id=uid).first()
    if not row_object:
    return JsonResponse({"status": False, 'error': "数据不存在"})

    # 从数据库中获取到一个对象 row_object
    result = {
    "status": True,
    "data": {
    "title": row_object.title,
    "price": row_object.price,
    "status": row_object.status,
    }
    }0
    return JsonResponse({"status": True, "data": result})
    """

    # 方式二
    uid = requeset.GET.get("uid")
    row_dict = models.Order.objects.filter(id=uid).values("title","price","status").first()
    if not row_dict:
    return JsonResponse({"status": False, 'error': "数据不存在"})

    # 从数据库中获取到一个对象 row_object
    result = {
    "status": True,
    "data": row_dict,
    }
    return JsonResponse(result)


    @csrf_exempt
    def order_edit(request):
    """编辑订单"""
    uid = request.GET.get("uid")
    row_object = models.Order.objects.filter(id=uid).first()
    if not row_object:
    return JsonResponse({"status": False, 'tips': "数据不存在"})
    form = OrderModelForm(data=request.POST, instance=row_object)
    if form.is_valid():
    form.save()
    return JsonResponse({"status": True})
    return JsonResponse({"status": False, 'error': form.errors})
  • 路径