探秘 Django 专业之道

news2025/1/11 4:12:09

一、Django项目开发

1.web框架底层

1.1 网络通信

在这里插入图片描述
注意:局域网
在这里插入图片描述
个人一般写程序,想要让别人访问:阿里云、腾讯云。

  • 去云平台租服务器(含公网IP)
  • 程序放在云服务器

先以局域网为例
在这里插入图片描述

  • 我的电脑【服务端】
import socket

# 1.监听本机的IP和端口
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('127.0.0.1', 8001))  # 我自己的电脑IP,端口8001

# 2.让多少人等待
sock.listen(5)

while True:
    # 3.等待连接请求的申请,有人来连接(阻塞)
    conn, addr = sock.accept()

    # 4.连接成功后立即发送
    conn.sendall("欢迎使用xx系统".encode("utf-8"))

    # 5.断开连接
    conn.close()


# 6.停止服务端程序
sock.close()
  • 女朋友的电脑(同一个局域网)【客户端】
import socket

# 1. 向指定IP发送连接请求
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('192.168.10.3', 8001))

# 2. 接收你发的消息
message = client.recv(1024)
print(message.decode("utf-8"))

# 3.断开连接
client.close()
  • 姓王的好兄弟【客户端】
import socket

# 1. 向指定IP发送连接请求
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('192.168.10.3', 8001))

# 2. 接收你发的消息
message = client.recv(1024)
print(message.decode("utf-8"))

# 3.断开连接
client.close()

我们自己写时,通过socket模块可以实现网络上的两端进行通信。

1.2 常见软件架构

  • bs架构
浏览器:充当客户端
服务器:网站
  • cs架构,开发应用程序,例如:QQ、Pycharm、网易云音乐(安装在电脑上的软件)
客户端:安装在电脑上的软件。 网易云音乐
服务端:网易服务器

1.3 快速自己写以为网站(不能用django、flask等)

import socket

# 1.监听本机的IP和端口
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('192.168.0.6', 9000))  # 我自己的电脑IP,端口8001

# 2.让多少人等待
sock.listen(5)

while True:
    # 3.等待连接请求的申请,有人来连接(阻塞) -> 登录浏览器来连接我
    conn, addr = sock.accept()

    # 4.收到浏览器发送的消息
    buf = conn.recv(2048)
    print(buf)

    # 5.给浏览器返回数据
    conn.send(b"HTTP/1.1 200 OK\r\n\r\n")
    conn.send(b"Hello, World")

    # 6.断开连接
    conn.close()

# 6.停止服务端程序
sock.close()

2. web框架

常见的web框架:django、flask、tornado、sanic、fastapi…

在这里插入图片描述
web应用程序:

  • 用户网络通信的socket
  • web框架
  • 业务开发

以django为例:

  • wsgiref模块、uwsgi、daphne -> 本质上都是socket实现。
  • 原来实现了框架

以flask为例:

  • werkzurg、uwsgi、…
  • flask框架

以tornado为例:

  • tornado、werkzurg、uwsgi、…
  • 框架

2.1 wsgiref

from wsgiref.simple_server import make_server


def run_server(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return [bytes('<h1>Hello, web!</h1>', encoding='utf-8'), ]


if __name__ == '__main__':
    httpd = make_server('127.0.0.1', 8000, run_server)
    httpd.serve_forever()

2.2 werkzeug

pip install werkzeug
from werkzeug.wrappers import Response


def application(environ, start_response):
    response = Response('Hello World!', mimetype='text/plain')
    return response(environ, start_response)


if __name__ == '__main__':
    from werkzeug.serving import run_simple

    run_simple('localhost', 4000, application)

2.3 各框架的区别

django、flask、tornado、sanic、fastapi..
  • 内部集成功能的多少
    • django,内部提供了很多组件。 【相对大】
    • flask、tornado、sanic、fastapi… 本身自己功能很少+第三方组件。【相对小】
  • 同步框架 vs 异步非阻塞
    • 异步非阻塞:tornado、sanic、fastapi、django
    • 同步:django、flask、bottle、webpy…
1.同步框架:django、flask
2.tornado,异步非阻塞,特别NB。
	- 同步:常见应用。
	- 异步:IO应用 + conroutine装饰器 + redis/MySQL/...
3.sanic,路飞小猿圈平台
4.fastapi
	- 参考flask
	- py最新注解
	- restfulAPI
	- 异步
	
目前不看好:
	- 增加编程的难度,功能&效率
	- 项目中不会有那么IO操作 ---> 100功能/2-IO ---> celery

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

二、命令行以及Pycharm创建app、创建虚拟环境

1.django框架

1.1 安装

pip install django==3.2

1.2 命令行

  • 创建项目
cd 指定目录
django-admin startproject 项目名
mysite
├── manage.py              [项目的管理工具]  
└── mysite
    ├── __init__.py
    ├── settings.py        【配置文件,只有一部分。程序启动时,先读取django内部配置,再读settings.py】
    ├── urls.py			   【主路由,在里面编写  /xxx/xxx/xxx ---> index 】
    ├── asgi.py            【异步】
    └── wsgi.py            【同步,主】
  • 编写代码 urls.py
from django.contrib import admin
from django.urls import path

from django.shortcuts import HttpResponse

def info(request):
    print("请求来执行了")
    return HttpResponse("xxxx")

def xxxx(request):
    print("请求来执行了")
    return HttpResponse("。。。。。。")

urlpatterns = [
    # path('admin/', admin.site.urls),
    path('api/index/', info),
    path('api/show/', xxxx),
]
  • 运行
cd 项目
python3.9 manage.py runserver
python3.9 manage.py runserver 127.0.0.1:8000
python3.9 manage.py runserver 127.0.0.1:9000
  • app概念
cd 项目
python manage.py startapp 名字
mysite
├── manage.py              [项目的管理工具]  
├── web
    ├── __init__.py
    ├── views.py           [视图函数]
    ├── models.py          [ORM,基于models可以对数据库进行简便的操作]
    ...
└── mysite
    ├── __init__.py
    ├── settings.py        【配置文件,只有一部分。程序启动时,先读取django内部配置,再读settings.py】
    ├── urls.py			   【主路由,在里面编写  /xxx/xxx/xxx ---> index 】
    ├── asgi.py            【异步】
    └── wsgi.py            【同步,主】
mysite
├── manage.py
├── mysite
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── web
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── migrations
    │   └── __init__.py
    ├── models.py
    ├── tests.py
    └── views.py

1.3 Pycharm

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

django-admin startproject 项目名称

cd 项目目录
python manage.py startapp
python manage.py runserver

2. 虚拟环境

2.1 创建虚拟环境 - 命令行

  • venv,Python官方用于创建虚拟环境的工具。
cd xxx/xxx/crm
python3.9 -m venv ddd
python3.7 -m venv xxxx
python3.7 -m venv /xxx/xxx/xxx/xx/ppp
  • virtualenv 【推荐】
pip install virtualenv
cd /xxx/xx/
virtualenv ddd --python=python3.9
virtualenv /xxx/xx/ddd --python=python3.7

操作:

  • F:\envs\ 创建虚拟环境。
cd F:\envs
virtualenv crm --python=python3.9

在这里插入图片描述

  • 激活虚拟环境
  • win
cd F:\envs\crm\Scripts
activate
  • mac
source /虚拟环境目录/bin/activate
  • 安装包
pip install 包名
  • 创建django项目 `D:\project\crm
cd D:\project
django-admin startproject crm
D:\project\crm
├── manage.py              [项目的管理工具]  
└── crm
    ├── __init__.py
    ├── settings.py        【配置文件,只有一部分。程序启动时,先读取django内部配置,再读settings.py】
    ├── urls.py			   【主路由,在里面编写  /xxx/xxx/xxx ---> index 】
    ├── asgi.py            【异步】
    └── wsgi.py            【同步,主】
python manage.py startapp xxxx
python manage.py runserver 
  • 退出虚拟环境
deactivate

在这里插入图片描述

2.2 Pycharm项目+虚拟环境

在这里插入图片描述
.venv:隐藏文件夹

  • 在虚拟环境中安装 requests
pip install requests

在这里插入图片描述

2.3 django+虚拟环境【最新】

pip install django

在这里插入图片描述
注意:创建django最新版可以。

2.3.1 django+虚拟环境【指定版本】

在这里插入图片描述

pip install django==3.2

在这里插入图片描述

django-admin startproject Django
这么命令会把Django项目嵌套着多了一层目录放进去,不是我们想要的
django-admin startproject Django .
我们想要的是将manage.py和Django这个目录放在当前这个项目目录

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

3.关于创建app

  • 项目只需要一个app,目录机构的建议。
    在这里插入图片描述
  • 项目只需要一个app,目录结构的建议。
day002
	.venv
    day002
    	...
        ...
    manage.py
    apps
    	web
        backend
        api

先在apps目录下面创建api、backend、web三个目录,然后使用下面命令,完成之后修改apps下面的apps.py文件,修改为:name = 'apps.api',其他两个也一样
在这里插入图片描述

4.关于纯净版

在这里插入图片描述

总结

知道如何基于pycharm+虚拟环境+业务场景 -> 创建django项目。

问题:给别人的代码+requirements.txt

三、模板介绍、静态文件、重定向以及相关案例

1.快速上手

  • 确保app已注册 【settings.py】
    在这里插入图片描述

  • 编写URL和视图函数对应关系 【urls.py】
    在这里插入图片描述

  • 编写视图函数 【views.py】
    在这里插入图片描述

  • 启动django项目

    • 命令行启动
      python manage.py runserver
      
    • Pycharm启动
      在这里插入图片描述

1.1 再写一个页面

在这里插入图片描述

2. templates模板

在这里插入图片描述

2.1 静态文件

2.1.1 static目录
  • 在app目录下创建static文件夹
    在这里插入图片描述
2.1.2 引用静态文件

在这里插入图片描述

3. 模板语法

本质上:在HTML中写一些占位符,由数据对这些占位符进行替换和处理。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

案例:伪联通新闻中心

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

4.请求和响应

在这里插入图片描述
关于重定向:
在这里插入图片描述

案例:用户登录

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
报上面错误的话要在.html里面加上{% csrf_token %}就可以了

在这里插入图片描述

四、Django操作数据库

1.数据库操作

  • MySQL数据库 + pymysql
import pymysql

# 1.连接MySQL
conn = pymysql.connect(host="127.0.0.1", port=3306, user='root', passwd="root123", charset='utf8', db='unicom')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

# 2.发送指令
cursor.execute("insert into admin(username,password,mobile) values('wupeiqi','qwe123','15155555555')")
conn.commit()

# 3.关闭
cursor.close()
conn.close()
  • Django开发操作数据库更简单,内部提供了ORM框架。
    在这里插入图片描述

1.1 安装第三方模块

pip install mysqlclient

在这里插入图片描述

1.2 ORM

  • 创建、修改、删除数据库中的表(不用你写SQL语句)。 【无法创建数据库】
  • 操作表中的数据(不用写SQL语句)。
1.2.1 自己创建数据库
  • 启动MySQL服务
  • 自带工具创建数据库
create database gx_day15 DEFAULT CHARSET utf8 COLLATE utf8_general_ci;

在这里插入图片描述

1.2.2 django连接数据库

在settings.py文件中进行配置和修改

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'gx_day15',  # 数据库名字
        'USER': 'root',
        'PASSWORD': 'root123',
        'HOST': '127.0.0.1',  # 那台机器安装了MySQL
        'PORT': 3306,
        'OPTIONS': {
            "init_command": "SET sql_mode='STRICT_TRANS_TABLES'"
        }
    }
}

在这里插入图片描述

1.2.3 django操作表
  • 创建表
  • 删除表
  • 修改表
    创建表:在models.py文件中
    在这里插入图片描述
create table app01_userinfo(
    id bigint auto_increment primary key,
    name varchar(32),
    password varchar(64),
    age int
)

执行命令:

python manage.py makemigrations
python manage.py migrate

注意:app需要提前注册。

在这里插入图片描述
在表中新增列时,由于已存在列中可能已有数据,所以新增列必须要指定新增列对应的数据

以后在开发中如果想要对表结构进行调整:

  • 在models.py文件中操作类即可。
  • 命令
python manage.py makemigrations
python manage.py migrate
1.2.4 表中的数据
#### 1.新建 ####
Department.objects.create(title="销售部")
Department.objects.create(title="IT部")
Department.objects.create(title="运营部")
UserInfo.objects.create(name="武沛齐", password="123", age=19)
UserInfo.objects.create(name="朱虎飞", password="666", age=29)
UserInfo.objects.create(name="吴阳军", password="666")

#### 2.删除 ####
UserInfo.objects.filter(id=3).delete()
Department.objects.all().delete()

#### 3.获取数据 ####
# 3.1 获取符合条件的所有数据
data_list = [对象,对象,对象]  QuerySet类型
data_list = UserInfo.objects.all()
for obj in data_list:
    print(obj.id, obj.name, obj.password, obj.age)

data_list = [对象,]
data_list = UserInfo.objects.filter(id=1)
print(data_list)
# 3.1 获取第一条数据【对象】
row_obj = UserInfo.objects.filter(id=1).first()
print(row_obj.id, row_obj.name, row_obj.password, row_obj.age)


#### 4.更新数据 ####
UserInfo.objects.all().update(password=999)
UserInfo.objects.filter(id=2).update(age=999)
UserInfo.objects.filter(name="朱虎飞").update(age=999)

五、案例:员工管理系统–部门管理

员工管理系统(部门管理)

1.新建项目

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

2.创建app

python manage.py startapp app01

在这里插入图片描述

2.1 注册app

在这里插入图片描述

3. 设计表结构(django)

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

from django.db import models


class Department(models.Model):
    """部门表"""
    title = models.CharField(verbose_name="标题", max_length=32)


class UserInfo(models.Model):
    """员工表"""
    name = models.CharField(verbose_name="姓名", max_length=32)
    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="入职时间")

    # 1.约束
    # to:与那一张表关联
    # to_field: 表中的那一列关联

    # 2.django内部会把depart自动生成depart_id
    depart = models.ForeignKey(to="Department", to_field="id")

    # 3.部门表被删除
    # 3.1 级联删除
    # depart = models.ForeignKey(to="Department", to_field="id", on_delete=models.CASCADE)
    # 3.2 置空
    # depart = models.ForeignKey(to="Department", to_field="id", null=True, blank=True, on_delete=models.SET_NULL)

    # 创建性别
    # 在django中做的约束,与数据库无关
    gender_choices = (
        (1, '男'),
        (2, '女'),
    )
    gender = models.SmallIntegerField(verbose_name="性别", choices=gender_choices)

4. 在MySQL中生成表

create database gx_day16 DEFAULT CHARSET utf8 COLLATE utf8_general_ci;

在这里插入图片描述

  • django命令生成数据库表
python manage.py makemigrations
python manage.py migrate

在这里插入图片描述

5. 静态文件管理

static目录
在这里插入图片描述

6. 部门管理

体验,最原始方法来做。

Django中提供Form和ModelForm组件(方便)

在这里插入图片描述

6.1 部门列表
<!--
@version : python 3.8
@author : Stara
@file : xxx.html
@time : 2023-10-28 下午13:20
-->
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>部门列表</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.min.css' %}">
    <style>
        .navbar{
            border-radius: 0;
        }
    </style>
</head>
<body>
<nav class="navbar navbar-default">
  <div class="container">
    <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="#">link</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">Stara<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>
    <div class="container">
        <div style="margin-bottom: 10px">
            <a class="btn btn-success" href="#">
                <span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
                新建部门
            </a>
        </div>
        <div class="panel panel-default">
        <div class="panel-heading">
          <span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
            部门列表
        </div>
        <table class="table table-bordered">
        <thead>
          <tr>
            <th>ID</th>
            <th>名称</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <th>1</th>
            <td>销售部</td>
            <td>
                <a class="btn btn-primary btn-xs">编辑</a>
                <a class="btn btn-danger btn-xs">删除</a>
            </td>

          </tr>
        </tbody>
      </table>
        </div>
    </div>
</div>

<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.min.js' %}"></script>
</body>
</html>

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

6.2 添加部门
6.2.1 添加部门页面

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
第一种:
在这里插入图片描述

<!--
@version : python 3.8
@author : Stara
@file : xxx.html
@time : 2023-10-28 下午13:20
-->
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>添加部门</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.min.css' %}">
    <style>
        .navbar{
            border-radius: 0;
        }
    </style>
</head>
<body>

<nav class="navbar navbar-default">
  <div class="container">
    <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="#">link</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">Stara<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>
    <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">
                 <h3 class="panel-title"> 新建部门 </h3>
            </div>
            <div class="panel-body">
               <form class="form-horizontal">
                    <div class="form-group">
                        <label  class="col-sm-2 control-label">标题</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" placeholder="标题" name="title">
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="col-sm-offset-2 col-sm-10">
                            <button type="submit" class="btn btn-primary">保 存</button>
                        </div>
                    </div>
                </form>
            </div>
        </div>
    </div>
</div>


<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.min.js' %}"></script>
</body>
</html>

第二种:
在这里插入图片描述

<!--
@version : python 3.8
@author : Stara
@file : xxx.html
@time : 2023-10-28 下午13:20
-->
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>添加部门</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.min.css' %}">
    <style>
        .navbar{
            border-radius: 0;
        }
    </style>
</head>
<body>

<nav class="navbar navbar-default">
  <div class="container">
    <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="#">link</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">Stara<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>
    <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title"> <span style="font-weight:bold;">新建部门</span> </h3>
            </div>
            <div class="panel-body">
               <form>
                     <div class="form-group">
                        <labe><span style="font-weight:bold;">标题</span></labe>
                        <input type="text" class="form-control" id="exampleInputEmail1" placeholder="标题" name="title"/>
                    </div>
                   <button type="submit" class="btn btn-primary">提交</button>
                </form>
            </div>
        </div>
    </div>
</div>


<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.min.js' %}"></script>
</body>
</html>
6.2.2 添加部门

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

6.2.3 删除部门

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

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

6.3 编辑部门

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

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

7. 模板的继承

7.1编辑部门

定义模板layout.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{% static 'plugin...min.css' %}">
    {% block css %}{% endblock %}
</head>
<body>
    <h1>标题</h1>
    <div>
        {% block content %}{% endblock %}
    </div>
    <h1>底部</h1>
    
    <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
    {% block js %}{% endblock %}
</body>
</html>

继承模板:

{% extends 'layout.html' %}

{% block css %}
	<link rel="stylesheet" href="{% static 'pluxxx.css' %}">
	<style>
		...
	</style>
{% endblock %}


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


{% block js %}
	<script src="{% static 'js/jqxxxin.js' %}"></script>
{% endblock %}

六、案例:员工管理系统–用户管理

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

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

{% extends 'layout.html' %}

{% block content %}
    <div class="container">
        <div style="margin-bottom: 10px">
            <a class="btn btn-success" href="#">
                <span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
                新建用户
            </a>
        </div>
        <div class="panel panel-default">
        <div class="panel-heading">
          <span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
            用户列表
        </div>
        <table class="table table-bordered">
        <thead>
          <tr>
            <th>ID</th>
            <th>姓名</th>
            <th>密码</th>
            <th>年龄</th>
            <th>余额</th>
            <th>入职时间</th>
            <th>性别</th>
            <th>所属部门</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>

          <tr>
            <th>id</th>
            <td>xxx</td>
            <td>xxx</td>
            <td>xxx</td>
            <td>xxx</td>
            <td>xxx</td>
            <td>xxx</td>
            <td>xxx</td>
            <td>
                <a class="btn btn-primary btn-xs" href="#">编辑</a>
                <a class="btn btn-danger btn-xs" href="#">删除</a>
            </td>

          </tr>
        </tbody>
      </table>
        </div>
    </div>

{% endblock %}

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

1.用户管理

insert into app01_userinfo(name,password,age,account,create_time,gender,depart_id) values("韩超","666",23,100.68,"2020-01-11",2,1);

insert into app01_userinfo(name,password,age,account,create_time,gender,depart_id) values("刘东","123",23,100.68,"2010-11-11",1,2);

insert into app01_userinfo(name,password,age,account,create_time,gender,depart_id) values("朱虎飞","999",33,9900.68,"2021-05-11",1,1);
+-------------+---------------+------+-----+---------+----------------+
| Field       | Type          | Null | Key | Default | Extra          |
+-------------+---------------+------+-----+---------+----------------+
| id          | bigint(20)    | NO   | PRI | NULL    | auto_increment |
| name        | varchar(16)   | NO   |     | NULL    |                |
| password    | varchar(64)   | NO   |     | NULL    |                |
| age         | int(11)       | NO   |     | NULL    |                |
| account     | decimal(10,2) | NO   |     | NULL    |                |
| create_time | datetime(6)   | NO   |     | NULL    |                |
| gender      | smallint(6)   | NO   |     | NULL    |                |
| depart_id   | bigint(20)    | NO   | MUL | NULL    |                |
+-------------+---------------+------+-----+---------+----------------+

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
传入HTML模板中:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2 新建用户

2.1 原始方式理思路:不会采用(本质)【麻烦】

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

{% extends 'layout.html' %}
{% block content %}
    <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title"> <span style="font-weight:bold;">新建用户</span> </h3>
            </div>
            <div class="panel-body">
               <form method="post">
                   {% csrf_token %}
                     <div class="form-group">
                        <labe><span style="font-weight:bold;">姓名</span></labe>
                        <input type="text" class="form-control" placeholder="姓名"/>
                    </div>
                    <div class="form-group">
                        <labe><span style="font-weight:bold;">密码</span></labe>
                        <input type="text" class="form-control" placeholder="密码"/>
                    </div>
                    <div class="form-group">
                        <labe><span style="font-weight:bold;">年龄</span></labe>
                        <input type="text" class="form-control" placeholder="年龄"/>
                    </div>
                    <div class="form-group">
                        <labe><span style="font-weight:bold;">余额</span></labe>
                        <input type="text" class="form-control" placeholder="余额"/>
                    </div>
                    <div class="form-group">
                        <labe><span style="font-weight:bold;">入职时间</span></labe>
                        <input type="text" class="form-control" placeholder="入职时间"/>
                    </div>
                    <div class="form-group">
                        <labe><span style="font-weight:bold;">性别</span></labe>
                        <select class="form-control">
                           {% for item in gender_choices %}
                               <option value="{{ item.0 }}">{{ item.1 }}</option>
                            {% endfor %}
                        </select>
                    </div>
                    <div class="form-group">
                        <labe><span style="font-weight:bold;">部门</span></labe>
                         <select class="form-control">
                             {% for item in depart_list %}
                                <option value="{{ item.id }}">{{ item.title }}</option>
                            {% endfor %}
                        </select>
                    </div>
                   <button type="submit" class="btn btn-primary">提交</button>
                </form>
            </div>
        </div>
    </div>
{% endblock %}

在这里插入图片描述
在这里插入图片描述
提交:

  • 定义name属性
    在这里插入图片描述
  • GET请求POST提交,添加到数据库中,返回到用户列表页面
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
2.2 Django组件
- Form组件(小简便)
- ModelForm组件(最简便)
2.2.1 初识Form
1. views.py
class MyForm(Form):
    user = forms.CharField(widget=forms.Input)
    pwd = form.CharFiled(widget=forms.Input)
    email = form.CharFiled(widget=forms.Input)
    account = form.CharFiled(widget=forms.Input)
    create_time = form.CharFiled(widget=forms.Input)
    depart = form.CharFiled(widget=forms.Input)
    gender = form.CharFiled(widget=forms.Input)


def user_add(request):
    if request.method == "GET":
        form = MyForm()
        return render(request, 'user_add.html',{"form":form})
2. user_add.html
<form method="post">
    {% for field in form%}
    	{{ field }}
    {% endfor %}
    <!-- <input type="text"  placeholder="姓名" name="user" /> -->
</form>
<form method="post">
    {{ form.user }}
    {{ form.pwd }}
    {{ form.email }}
    <!-- <input type="text"  placeholder="姓名" name="user" /> -->
</form>
2.2.2 ModelForm(推荐)
1. models.py
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. views.py
class MyForm(ModelForm):
    xx = form.CharField*("...")
    class Meta:
        model = UserInfo
        fields = ["name","password","age","xx"]


def user_add(request):
    if request.method == "GET":
        form = MyForm()
        return render(request, 'user_add.html',{"form":form})
3. user_add.html
<form method="post">
    {% for field in form%}
    	{{ field }}
    {% endfor %}
    <!-- <input type="text"  placeholder="姓名" name="user" /> -->
</form>
<form method="post">
    {{ form.user }}
    {{ form.pwd }}
    {{ form.email }}
    <!-- <input type="text"  placeholder="姓名" name="user" /> -->
</form>

3.用户——添加(ModelForm)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
前端界面user_moduser_model_form_add.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form method="post">
    {% csrf_token %}
    {% for field in form %}
        {{ field.label }} : {{ field }}
    {% endfor %}

</form>

</body>
</html>

这样写后我们只需要在views.py和models.py里面添加
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
{{ field.label }} 是表单字段的文本标签,{{ field }} 则是一个 HTML 元素,表示该字段的表单控件,如输入框、下拉列表等。label 表示表单中每个字段的文本标签

3.1 关联数据

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

3.2 集成到bootstrip

user_model_form_add.html

{% extends 'layout.html' %}
{% block content %}
    <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title"><span style="font-weight:bold;">新建用户</span></h3>
            </div>
            <div class="panel-body">
                <form method="post">
                    {% csrf_token %}
                    {% for field in form %}
                        <div class="form-group">
                            <labe><span style="font-weight:bold;">{{ field.label }}</span></labe>
                            {{ field }}
                            {# <input type="text" class="form-control" placeholder="姓名" name="user"/>#}
                        </div>
                    {% endfor %}
                    <button type="submit" class="btn btn-primary">提交</button>
                </form>
            </div>
        </div>
    </div>
{% endblock %}

在这里插入图片描述
在这里插入图片描述
添加样式:
方式一:
在这里插入图片描述
方式二:
在这里插入图片描述
在这里插入图片描述你也可以某个字段不加:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.2 添加和错误提示

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

在这里插入图片描述
在这里插入图片描述
做更多的校验
在这里插入图片描述
在这里插入图片描述
Django(六)

4.编辑用户

  • 点击编辑,跳转到编辑页面(将编辑行的ID携带过去)。
  • 编辑页面(默认数据,根据ID获取并设置到页面中)
  • 提交:
    • 错误提示
    • 数据校验
    • 在数据库更新
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

user_edit.html

{% extends 'layout.html' %}
{% block content %}
    <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title"><span style="font-weight:bold;">编辑用户</span></h3>
            </div>
            <div class="panel-body">
                <form method="post" novalidate>
                    {% csrf_token %}
                    {% for field in form %}
                        <div class="form-group">
                            <labe><span style="font-weight:bold;">{{ field.label }}</span></labe>
                            {{ field }}
                            <span style="color: red">{{ field.errors.0 }}</span>
                        </div>
                    {% endfor %}
                    <button type="submit" class="btn btn-primary">提交</button>
                </form>
            </div>
        </div>
    </div>
{% endblock %}

在这里插入图片描述
展示默认数据
在这里插入图片描述
在这里插入图片描述编辑修改
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.删除

user_list.html
在这里插入图片描述

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

七、员工管理系统-靓号管理

1.靓号管理

1.1 表结构

在这里插入图片描述
根据表结构的需求,在models.py中创建类(由类生成数据库中的表)。

class PrettyNum(models.Model):
    """ 靓号表 """
    mobile = models.CharField(verbose_name="手机号", max_length=11)
    # 想要允许为空 null=True, blank=True
    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)

自己在数据模拟创建一些数据:

insert into app01_prettynum(mobile,price,level,status)values("111111111",19,1,1);

1.2 靓号列表

  • URL
  • 函数
    • 获取所有靓号
    • 结合HTML+render将靓号罗列出来
      id	号码	价格	级别(中文)	状态(中文)
      

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

pretty_list.html

{% extends 'layout.html' %}
{% block content %}
    <div class="container">
        <div style="margin-bottom: 10px">
            <a class="btn btn-success" href="#">
                <span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
                新建靓号
            </a>
        </div>
        <div class="panel panel-default">
            <div class="panel-heading">
                <span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
                用户列表
            </div>
            <table class="table table-bordered">
                <thead>
                <tr>
                    <th>ID</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.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="#">编辑</a>
                            <a class="btn btn-danger btn-xs" href="#">删除</a>
                        </td>

                    </tr>
                {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
{% endblock %}

layout.html里面添加如下图
在这里插入图片描述

1.3 新建靓号

  • 列表页面跳转:/pretty/add/

  • URL

  • ModelForm类

    from django import forms
    
    class PrettyModelForm(forms.ModelForm):
    	...
    
  • 函数

    • 实例化类的对象
    • 通过render将对象传入到HTML中。
    • 模板的循环展示所有的字段。
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
{% extends 'layout.html' %}
{% block content %}
    <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title"><span style="font-weight:bold;">新建靓号</span></h3>
            </div>
            <div class="panel-body">
                <form method="post" novalidate>		 # 如果没写novalidate浏览器会做校验
                    {% csrf_token %}
                    {% for field in form %}
                        <div class="form-group">
                            <labe><span style="font-weight:bold;">{{ field.label }}</span></labe>
                            {{ field }}
                            <span style="color: red">{{ field.errors.0 }}</span>
                        </div>
                    {% endfor %}
                    <button type="submit" class="btn btn-primary">提交</button>
                </form>
            </div>
        </div>
    </div>
{% endblock %}

在这里插入图片描述

  • 点击提交
    • 数据校验
    • 保存到数据库
    • 跳转回靓号列表
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      可以为空,输入也能提交但是这样需要格式校验(手机号11位)
      在这里插入图片描述

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

1.4 编辑靓号

在这里插入图片描述

  • 列表页面:`/pretty/数字/edit/
  • URL
  • 函数
    • 根据ID获取当前编辑的对象
    • ModelForm配合,默认显示数据。
    • 提交修改。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
不允许手机号重复

  • 添加:【正则表达式】【手机号不能存在】
# [obj,obj,obj] 对象
queryset = models.PrettyNum.objects.filter(mobile="1888888888")

obj = models.PrettyNum.objects.filter(mobile="1888888888").first()

# True/False
exists = models.PrettyNum.objects.filter(mobile="1888888888").exists()	# 钩子方法里面操作
  • 编辑:【正则表达式】【手机号不能存在】
排除自己以外,其他的数据是否手机号是否重复?

# id!=2 and mobile='1888888888'
models.PrettyNum.objects.filter(mobile="1888888888").exclude(id=2)

在这里插入图片描述

在这里插入图片描述

1.5 删除靓号

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

1.6 搜索手机号

models.PrettyNum.objects.filter(mobile="19999999991",id=12)

data_dict = {"mobile":"19999999991","id":123}
models.PrettyNum.objects.filter(**data_dict)	#如果在filter里面放了空字典就相当于获取所有的

在这里插入图片描述

models.PrettyNum.objects.filter(id=12)       # 等于12
models.PrettyNum.objects.filter(id__gt=12)   # 大于12
models.PrettyNum.objects.filter(id__gte=12)  # 大于等于12
models.PrettyNum.objects.filter(id__lt=12)   # 小于12
models.PrettyNum.objects.filter(id__lte=12)  # 小于等于12

data_dict = {"id__lte":12}
models.PrettyNum.objects.filter(**data_dict)
models.PrettyNum.objects.filter(mobile="999")               # 等于
models.PrettyNum.objects.filter(mobile__startswith="1999")  # 筛选出以1999开头
models.PrettyNum.objects.filter(mobile__endswith="999")     # 筛选出以999结尾
models.PrettyNum.objects.filter(mobile__contains="999")     # 筛选出包含999

data_dict = {"mobile__contains":"999"}
models.PrettyNum.objects.filter(**data_dict)

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

1.7 分页

queryset = models.PrettyNum.objects.all()

queryset = models.PrettyNum.objects.filter(id=1)[0:10]


# 第1页
queryset = models.PrettyNum.objects.all()[0:10]

# 第2页
queryset = models.PrettyNum.objects.all()[10:20]

# 第3页
queryset = models.PrettyNum.objects.all()[20:30]
  • 分页的逻辑和处理规则
  • 封装分页类
    • 从头到尾开发
    • 写项目用【pagination.py】公共组件。
      在这里插入图片描述

pagination.py

"""
自定义的分页组件,以后如果想要使用这个分页组件,你需要做如下几件事:

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

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

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

        context = {
            "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中传递的获取分页的参数,例如:/etty/list/?page=12
        :param plus: 显示当前页的 前或后几页(页码)
        """

        from django.http.request import QueryDict
        import copy
        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):
        # 计算出,显示当前页的前5页、后5页
        if self.total_page_count <= 2 * self.plus + 1:
            # 数据库中的数据比较少,都没有达到11页。
            start_page = 1
            end_page = self.total_page_count
        else:
            # 数据库中的数据比较多 > 11页。

            # 当前页<5时(小极值)
            if self.page <= self.plus:
                start_page = 1
                end_page = 2 * self.plus + 1
            else:
                # 当前页 > 5
                # 当前页+5 > 总页面
                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

        # 页码
        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 + 1):
            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])
            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">
                    <input name="page"
                           style="position: relative;float:left;display: inline-block;width: 80px;border-radius: 0;"
                           type="text" class="form-control" placeholder="页码">
                    <button style="border-radius: 0" class="btn btn-default" type="submit">跳转</button>
                </form>
            </li>
            """

        page_str_list.append(search_string)
        page_string = mark_safe("".join(page_str_list))
        return page_string

pretty_list.html

{% extends 'layout.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>
                </form>
            </div>

        </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>
                </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 class="clearfix">
            <ul class="pagination">
                {{ page_string }}
            </ul>

        </div>

    </div>
{% endblock %}

在这里插入图片描述
修改以下用户管理分页
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
修改部门管理分页
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.7.1 分页的关键步骤

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

1.8 时间插件

<link rel="stylesheet" href="static/plugins/bootstrap-3.4.1/css/bootstrap.css">
<link rel="stylesheet" href="static/plugins/bootstrap-datepicker/css/bootstrap-datepicker.css">


<input type="text" id="dt" class="form-control" placeholder="入职日期">



<script src="static/js/jquery-3.6.0.min.js"></script>
<script src="static/plugins/bootstrap-3.4.1/js/bootstrap.js"></script>
<script src="static/plugins/bootstrap-datepicker/js/bootstrap-datepicker.js"></script>
<script src="static/plugins/bootstrap-datepicker/locales/bootstrap-datepicker.zh-CN.min.js"></script>


<script>
    $(function () {
        $('#dt').datepicker({
            format: 'yyyy-mm-dd',
            startDate: '0',
            language: "zh-CN",
            autoclose: true
        });

    })
</script>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在ModelForm界面:
在这里插入图片描述

在这里插入图片描述

1.9 优化ModelForm和BootStrap

  • ModelForm可以帮助我们生成HTML标签。
例如:
class UserModelForm(forms.ModelForm):
    class Meta:
        model = models.UserInfo
        fields = ["name", "password",]

form = UserModelForm()
在HTML中只是生成了普通的input框没有bootstrap样式:
{{form.name}}      普通的input框
{{form.password}}  普通的input框
  • 定义插件
class UserModelForm(forms.ModelForm):
    class Meta:
        model = models.UserInfo
        fields = ["name", "password",]
        widgets = {
            "name": forms.TextInput(attrs={"class": "form-control"}),
            "password": forms.PasswordInput(attrs={"class": "form-control"}),
            "age": forms.TextInput(attrs={"class": "form-control"}),
        }
也可以这样写:

class UserModelForm(forms.ModelForm):
    name = forms.CharField(
        min_length=3,
        label="用户名",
        widget=forms.TextInput(attrs={"class": "form-control"})
    )

    class Meta:
        model = models.UserInfo
        fields = ["name", "password", "age"]
在HTML展示是可以有bootstrap样式的
{{form.name}}      BootStrap的input框
{{form.password}}  BootStrap的input框
问题在于这么写太繁琐了,所有我们重新定义init方法
  • 重新定义的init方法,批量设置
class UserModelForm(forms.ModelForm):
    class Meta:
        model = models.UserInfo
        fields = ["name", "password", "age",]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        # 循环ModelForm中的所有字段,给每个字段的插件设置
        for name, field in self.fields.items():
			field.widget.attrs = {
                "class": "form-control", 
                "placeholder": field.label
            }
优化:
class UserModelForm(forms.ModelForm):
    class Meta:
        model = models.UserInfo
        fields = ["name", "password", "age",]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        # 循环ModelForm中的所有字段,给每个字段的插件设置
        for name, field in self.fields.items():
            # 字段中有属性,保留原来的属性,没有属性,才增加。
            if field.widget.attrs:
				field.widget.attrs["class"] = "form-control"
				field.widget.attrs["placeholder"] = field.label
            else:
                field.widget.attrs = {
                    "class": "form-control", 
                    "placeholder": field.label
                }
再优化:
自定义类
class BootStrapModelForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 循环ModelForm中的所有字段,给每个字段的插件设置
        for name, field in self.fields.items():
            # 字段中有属性,保留原来的属性,没有属性,才增加。
            if field.widget.attrs:
				field.widget.attrs["class"] = "form-control"
				field.widget.attrs["placeholder"] = field.label
            else:
                field.widget.attrs = {
                    "class": "form-control", 
                    "placeholder": field.label
                }
让它继承:
class UserEditModelForm(BootStrapModelForm):
    class Meta:
        model = models.UserInfo
        fields = ["name", "password", "age",]
1.9.1 操作
  • 提取公共的类
    在这里插入图片描述
  • vews.py中找到所有的modelform继承并拆分出来
    在这里插入图片描述
  • vews.py文件中的业务按照类型拆分斌删除vews.py文件
    在这里插入图片描述
  • 关键点:修改urls.py文件
    在这里插入图片描述

八、案例:员工管理系统–管理员

1. 管理员操作

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

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

1.1 添加

from django.shortcuts import render, redirect

from app01 import models
from app01.utils.pagination import Pagination

from django import forms
from django.core.exceptions import ValidationError
from app01.utils.bootstrap import BootStrapModelForm
from app01.utils.encrypt 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


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})

在这里插入图片描述

1.2 编辑删除

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

1.3 重置密码

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

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

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

    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_reset(request, nid):
    """ 重置密码 """
    # 对象 / None
    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})

九、用户登录cookie和session、中间件处理以及动态生成图片验证码

1. 用户登录-Cookie和Session

什么是cookie和session?

cookie:
1.保存在浏览器上的键值对
2.发送请求时,自动携带
Session:
服务端存储信息,是一个概念,可以存在数据库等地

  • 发送HTTP请求或者HTTPS请求(无状态&短连接)
http://127.0.0.1:8000/admin/list/
https://127.0.0.1:8000/admin/list/

在这里插入图片描述

  • http无状态短连接:一次请求响应之后断开连接,再发请求重新连接服务端网站就不再知道是那个人了(新人)
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述

account.py

from django.shortcuts import render, HttpResponse, redirect
from django import forms
from app01.utils.bootstrap import BootStrapForm
from app01.utils.encrypt import md5
from app01 import models

class LoginForm(BootStrapForm):
    username = forms.CharField(
        label="用户名",
        widget=forms.TextInput,
        required=True,  # 必填不能为空
    )
    password = forms.CharField(
        label="密码",
        widget=forms.PasswordInput(render_value=True),  # render_value=True:保留输入错误的密码
        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():
        # 1.验证成功,获取到的用户名和密码
        # {'username': 'stara', 'password': '20010511'}
        # print(form.cleaned_data)
        # 2.去数据库校验用户名和密码是否正确(数据库密码是个密文,上面定义钩子方法),获取用户对象错误为None
        # {'username': 'stara', 'password': '72ed2c732c585b70e3d699a710623e07'}
        # print(form.cleaned_data)
        # admin_object = models.Admin.objects.filter(username=form.cleaned_data['username'], password=form.cleaned_data['password']).first() # 这样写可以但是我们已经知道是字典了
        admin_object = models.Admin.objects.filter(**form.cleaned_data).first()
        if not admin_object:
            # 展示错误信息
            form.add_error("password", "用户名或密码错误")
            # 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 HttpResponse("提交成功")
    return render(request, 'login.html', {'form': form})

在这里插入图片描述
login.html

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.min.css' %}">
    <style>
        .account {
            width: 400px;
            border: 1px solid #dddddd;
            border-radius: 5px;
            box-shadow: 5px 5px 20px #aaa;

            margin-left: auto;
            margin-right: auto;
            margin-top: 100px;
            padding: 20px 40px;
        }

        .account h2 {
            margin-top: 10px;
            text-align: center;
        }
    </style>
</head>
<body>
<div class="account">
    <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.password.errors.0 }}</span>
        </div>
        <input type="submit" value="登 录" class="btn btn-primary">
    </form>
</div>

</body>
</html>

在这里插入图片描述

1.1 登录

登录成功后:

  • cookie,随机字符串
  • session,用户信息

在其他需要登录才能访问的页面中,都需要加入:

def index(request):
    info = request.session.get("info")
    if not info:
        return redirect('/login/')

在这里插入图片描述

2.用户登录-中间件处理

在这里插入图片描述
正常执行:
在类里面经过中间件,中间件其实是一个类,类里面经过中间件的时候进来的是process_request方法,当请求进来之后会找到三个类一次执行process_request;如果都执行完了,在执行三个类里面的process_reaponse方法。
不正常执行:
如果执行到第二个中间件,不允许往后走,那么就会在第二个直接返回过去,用户就根本到达不了视图函数了,如果我们用户来访问的时候在第三个中间件前面写了一个中间件的类,在这个类里面写了一个process_request方法,我们在process_request里面判断(第二个类里面的process_request方法)当前用户是否已经登录了,如果登录继续往后走,没有登录让process_response(第二个类的方法)返回登录页面

  • 定义中间件
    在这里插入图片描述
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class M1(MiddlewareMixin):
    """ 中间件1 """

    def process_request(self, request):

        # 如果方法中没有返回值(返回None),继续向后走
        # 如果有返回值 HttpResponse、render 、redirect
        print("M1.process_request")
        return HttpResponse("无权访问")

    def process_response(self, request, response):
        print("M1.process_response")
        return response


class M2(MiddlewareMixin):
    """ 中间件2 """

    def process_request(self, request):
        print("M2.process_request")

    def process_response(self, request, response):
        print("M2.process_response")
        return response
  • 应用中间件 setings.py

在这里插入图片描述

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',
    'app01.middleware.auth.M1',
    'app01.middleware.auth.M2',
]
  • 在中间件的process_request方法
# 如果方法中没有返回值(返回None),继续向后走
# 如果有返回值 HttpResponse、render 、redirect,则不再继续向后执行。

在这里插入图片描述

2.1 中间件实现登录校验

  • 编写中间件
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse, redirect


class AuthMiddleware(MiddlewareMixin):

    def process_request(self, request):
        # 0.排除那些不需要登录就能访问的页面
        #   request.path_info 获取当前用户请求的URL /login/
        if request.path_info == "/login/":
            return

        # 1.读取当前访问的用户的session信息,如果能读到,说明已登陆过,就可以继续向后走。
        info_dict = request.session.get("info")
        print(info_dict)
        if info_dict:
            return

        # 2.没有登录过,重新回到登录页面
        return redirect('/login/')

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

  • 应用中间件
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',
    'app01.middleware.auth.AuthMiddleware',
]

3.用户认证-注销

def logout(request):
    """ 注销 """

    request.session.clear()

    return redirect('/login/')

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

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

4.获取登录后的用户信息

第一种方式:
在这里插入图片描述
第二种方式:在模板layout.html中
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.图片验证码

  • 基本逻辑代码(参考)
import random
 
def check_code(width=120, height=30, char_length=5, font_file='kumo.ttf', font_size=28):
    code = []
    img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
    draw = ImageDraw.Draw(img, mode='RGB')
 
    def rndChar():
        """
        生成随机字母   
        :return:
        """
        return chr(random.randint(65, 90))
 
    def rndColor():
        """
        生成随机颜色
        :return:
        """
        return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))
 
    # 写文字
    font = ImageFont.truetype(font_file, font_size)
    for i in range(char_length):
        char = rndChar()
        code.append(char)
        h = random.randint(0, 4)
        draw.text([i * width / char_length, h], char, font=font, fill=rndColor())
 
    # 写干扰点
    for i in range(40):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
 
    # 写干扰圆圈
    for i in range(40):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
        x = random.randint(0, width)
        y = random.randint(0, height)
        draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())
 
    # 画干扰线
    for i in range(5):
        x1 = random.randint(0, width)
        y1 = random.randint(0, height)
        x2 = random.randint(0, width)
        y2 = random.randint(0, height)
 
        draw.line((x1, y1, x2, y2), fill=rndColor())
 
    img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
    return img,''.join(code)
 
 
if __name__ == '__main__':
    # 1. 直接打开
    # img,code = check_code()
    # img.show()
 
    # 2. 写入文件
    # img,code = check_code()
    # with open('code.png','wb') as f:
    #     img.save(f,format='png')
 
    # 3. 写入内存(Python3)
    # from io import BytesIO
    # stream = BytesIO()
    # img.save(stream, 'png')
    # stream.getvalue()
 
    # 4. 写入内存(Python2)
    # import StringIO
    # stream = StringIO.StringIO()
    # img.save(stream, 'png')
    # stream.getvalue()
 
    pass

在这里插入图片描述

5.1 生成图片

login.html加上下面代码

 <div class="form-group">
            <label for="id_code">图片验证码</label>
            <div class="row">
                <div class="col-xs-7">
                   <input type="text" name="code" class="form-control" placeholder="图片验证码" required="" id="id_code">
                    <span style="color: red;">{{ form.code.errors.0 }}</span>
                </div>
                <div class="col-xs-5">
                    <img id="image_code" src="{% static 'img/code.jpg' %}" style="width: 125px;">
                </div>
            </div>
        </div>

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

5.2 动态生成图片

pip install pillow

首先Python生成随机验证码,需要使用PIL模块,接着,我们需要下载并准备适应验证码的字体文件。网络上有许多免费的字体可供选择,你可以选择一个合适的字体并进行下载。将字体文件保存在与你的Python脚本相同的目录下。然后,我们可以开始编写代码来生成随机验证码

博主自己下载了一些文件字体需要者可取,下载链接如下:
https://download.csdn.net/download/m0_69402477/88820707

import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter


def check_code(width=120, height=30, char_length=5, font_file='Monaco.ttf', font_size=28):  # 字体文件:Monaco.ttf
    code = []
    img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))    # 创建图片
    draw = ImageDraw.Draw(img, mode='RGB')

    def rndChar():
        """
        生成随机字母
        :return:
        """
        return chr(random.randint(65, 90))

    def rndColor():
        """
        生成随机颜色
        :return:
        """
        return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))

    # 写文字
    font = ImageFont.truetype(font_file, font_size)
    for i in range(char_length):
        char = rndChar()
        code.append(char)
        h = random.randint(0, 4)
        draw.text([i * width / char_length, h], char, font=font, fill=rndColor())

    # 写干扰点
    for i in range(40):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())

    # 写干扰圆圈
    for i in range(40):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
        x = random.randint(0, width)
        y = random.randint(0, height)
        draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())

    # 画干扰线
    for i in range(5):
        x1 = random.randint(0, width)
        y1 = random.randint(0, height)
        x2 = random.randint(0, width)
        y2 = random.randint(0, height)

        draw.line((x1, y1, x2, y2), fill=rndColor())

    img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
    return img, ''.join(code)


if __name__ == '__main__':
    img, code_str = check_code()    # 写在图片上的文字code_str
    print(code_str)

    with open('app01/static/img/code.png', 'wb') as f:
        img.save(f, format='png')

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

5.2.1在Django中调用
  • 在utils下创建一个文件code.py将随机生成验证码代码粘贴进去,把之前创建的.py文件删除,图片也删除,只留下字体
    在这里插入图片描述
  • code.py修改
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter


def check_code(width=120, height=30, char_length=5, font_file='Monaco.ttf', font_size=28):  # 字体文件:Monaco.ttf
    code = []
    img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))    # 创建图片
    draw = ImageDraw.Draw(img, mode='RGB')

    def rndChar():
        """
        生成随机字母
        :return:
        """
        return chr(random.randint(65, 90))

    def rndColor():
        """
        生成随机颜色
        :return:
        """
        return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))

    # 写文字
    font = ImageFont.truetype(font_file, font_size)
    for i in range(char_length):
        char = rndChar()
        code.append(char)
        h = random.randint(0, 4)
        draw.text([i * width / char_length, h], char, font=font, fill=rndColor())

    # 写干扰点
    for i in range(40):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())

    # 写干扰圆圈
    for i in range(40):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
        x = random.randint(0, width)
        y = random.randint(0, height)
        draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())

    # 画干扰线
    for i in range(5):
        x1 = random.randint(0, width)
        y1 = random.randint(0, height)
        x2 = random.randint(0, width)
        y2 = random.randint(0, height)

        draw.line((x1, y1, x2, y2), fill=rndColor())

    img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
    return img, ''.join(code)
  • 写url
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
5.2.2 图片验证码校验

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

十、Ajax的运用

1. Ajax请求

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

  • GET
  • POST

特点:页面刷新。

除此之外,也可以基于Ajax向后台发送请求(偷偷的发送请求)。

  • 依赖jQuery
  • 编写ajax代码
$.ajax({
    url:"发送的地址",
    type:"get",
    data:{
        n1:123,
        n2:456
    },
    success:function(res){
        console.log(res);
    }
})

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里只是console了一下,我们想要的是点击发送一个请求

在这里插入图片描述

发送一个请求:
在这里插入图片描述

1.1 GET请求

$.ajax({
    url: '/task/ajax/',   //发送的地址
    type: "get",          //发get请求
    data: {
            n1: 123,
            n2: 456
          },
          success: function (res) {   //登陆成功之后,自动执行success后面的函数,res是返回的值
              console.log(res);
          }
})

后台获取数据

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

1.2 POST请求

$.ajax({
    url: '/task/ajax/',   //发送的地址
    type: "post",          //发get请求
    data: {
            n1: 123,
            n2: 456
          },
          success: function (res) {   //登陆成功之后,自动执行success后面的函数,res是返回的值
              console.log(res);
          }
})

在这里插入图片描述
免除csrf_token认证
在这里插入图片描述
在这里插入图片描述
后台获取数据

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.3 修改前端代码jQuery形式关闭绑定事件

{% extends 'layout.html' %}

{% block content %}
    <div class="container">
        <h1>Ajax学习</h1>
        <h3>示例一</h3>
        <input id="btn1" type="button" class="btn-primary" value="点击">
    </div>

{% endblock %}
{% block js %}

    <script type="text/javascript">
        $(function () {
            // 页面框架加载完成之后直接执行
            bindBtn1Event();
        })

        function bindBtn1Event() {
            $("#btn1").click(function () {
                $.ajax({
                    url: '/task/ajax/',   //发送的地址
                    type: "post",          //发get请求
                    data: {
                        n1: 123,
                        n2: 456
                    },
                    success: function (res) {   //登陆成功之后,自动执行success后面的函数,res是返回的值
                        console.log(res);
                    }
                })
            })
        }


    </script>
{% endblock %}

1.4 ajax请求的返回值

一般会返回一个JSON格式(字符串里面套这个列表啥的)
在这里插入图片描述
在这里插入图片描述
前端界面可以获取到值:(前端得到字符串,后端是一个json数据)前端js里面针对json格式反序列化成js里面的对象
在这里插入图片描述
在这里插入图片描述

{% extends 'layout.html' %}

{% block content %}
    <div class="container">
        <h1>Ajax学习</h1>
        <h3>示例一</h3>
        <input id="btn1" type="button" class="btn-primary" value="点击">
    </div>

{% endblock %}
{% block js %}

    <script type="text/javascript">
        $(function () {
            // 页面框架加载完成之后直接执行
            bindBtn1Event();
        })

        function bindBtn1Event() {
            $("#btn1").click(function () {
                $.ajax({
                    url: '/task/ajax/',   //发送的地址
                    type: "post",          //发get请求
                    data: {
                        n1: 123,
                        n2: 456
                    },
                    dataType:"JSON",
                    success: function (res) {   //登陆成功之后,自动执行success后面的函数,res是返回的值
                        console.log(res);
                        console.log(res.status);
                        console.log(res.data);
                    }
                })
            })
        }

    </script>
{% endblock %}
import json

from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt


def task_list(request):
    """任务列表"""
    return render(request, 'task_list.html')


@csrf_exempt
def task_ajax(request):
    print(request.GET)
    print(request.POST)

    data_dict = {"status": True, "data": [11, 22, 33, 44]}
    return HttpResponse(json.dumps(data_dict))
    # return JsonResponse(data_dict)

1.5 案例2把input框里面的数据提交到后台

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

<h3>示例2</h3>
<input type="text" id="txtUser" placeholder="姓名"/>
<input type="text" id="txtAge" placeholder="年龄"/>
<input id="btn2" type="button" class="btn-primary" value="点击">
<script type="text/javascript">
        $(function () {
            // 页面框架加载完成之后直接执行
            bindBtn2Event();
        })
        function bindBtn2Event() {
            $("#btn2").click(function () {  //绑定click事件
                $.ajax({
                    url: '/task/ajax/',   //发送的地址
                    type: "post",          //发get请求
                    data: {
                        name: $("#txtUser").val(),  //数据不能写死,需要获取到值传入到后台
                        age: $("#txtAge").val()
                    },
                    dataType: "JSON",
                    success: function (res) {   //登陆成功之后,自动执行success后面的函数,res是返回的值
                        console.log(res);
                        console.log(res.status);
                        console.log(res.data);
                    }
                })
            })
        }
</script>

1.6 示例3

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

Ajax部分源代码

{% extends 'layout.html' %}

{% block content %}
    <div class="container">
        <h1>Ajax学习</h1>
        <h3>示例1</h3>
        <input id="btn1" type="button" class="btn-primary" value="点击1">

        <h3>示例2</h3>
        <input type="text" id="txtUser" placeholder="姓名"/>
        <input type="text" id="txtAge" placeholder="年龄"/>
        <input id="btn2" type="button" class="btn-primary" value="点击2">

        <h3>示例3</h3>
        <form id="form3">
            <input type="text" name="user" placeholder="姓名"/>
            <input type="text" name="age" placeholder="年龄"/>
            <input type="text" name="email" placeholder="邮箱"/>
            <input type="text" name="more" placeholder="介绍"/>
        </form>
        <input id="btn3" type="button" class="btn-primary" value="点击3">
    </div>

{% endblock %}
{% block js %}

    <script type="text/javascript">
        $(function () {
            // 页面框架加载完成之后直接执行
            bindBtn1Event();
            bindBtn2Event();
            bindBtn3Event();
        })

        function bindBtn1Event() {
            $("#btn1").click(function () {  //绑定click事件
                $.ajax({
                    url: '/task/ajax/',   //发送的地址
                    type: "post",          //发get请求
                    data: {
                        n1: 123,
                        n2: 456
                    },
                    dataType: "JSON",
                    success: function (res) {   //登陆成功之后,自动执行success后面的函数,res是返回的值
                        console.log(res);
                        console.log(res.status);
                        console.log(res.data);
                    }
                })
            })
        }

        function bindBtn2Event() {
            $("#btn2").click(function () {  //绑定click事件
                $.ajax({
                    url: '/task/ajax/',   //发送的地址
                    type: "post",          //发get请求
                    data: {
                        name: $("#txtUser").val(),  //数据不能写死,需要获取到值传入到后台
                        age: $("#txtAge").val()
                    },
                    dataType: "JSON",
                    success: function (res) {   //登陆成功之后,自动执行success后面的函数,res是返回的值
                        console.log(res);
                        console.log(res.status);
                        console.log(res.data);
                    }
                })
            })
        }

        function bindBtn3Event() {
            $("#btn3").click(function () {  //绑定click事件
                $.ajax({
                    url: '/task/ajax/',   //发送的地址
                    type: "post",          //发get请求
                    data: $("#form3").serialize(),  //自动将表单里面的所有输入框值全部获取到并且打包后发送到Django后台
                    dataType: "JSON",
                    success: function (res) {   //登陆成功之后,自动执行success后面的函数,res是返回的值
                        console.log(res);
                        console.log(res.status);
                        console.log(res.data);
                    }
                })
            })
        }
    </script>
{% endblock %}

创建一个任务,写一个面板里面写几个表单,将任务数据拿到后保存到数据库

1.创建面板

   <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">表单</div>
            <div class="panel-body">
                Panel content
            </div>
        </div>

在这里插入图片描述
在这里插入图片描述
2.创表
在这里插入图片描述

class Task(models.Model):
    """任务"""
    level_choice = (
        (1, "紧急"),
        (2, "重要"),
        (3, "临时")
    )
    level = models.SmallIntegerField(verbose_name="级别", choices=level_choice, default=1)
    title = models.CharField(verbose_name="标题", max_length=64)
    detail = models.TextField(verbose_name="详细信息")

    user = models.ForeignKey(verbose_name="负责人", to="Admin", on_delete=models.CASCADE)

在这里插入图片描述
3.展示ModelForm
在这里插入图片描述

from app01.utils.bootstrap import BootStrapModelForm
from app01 import models
class TaskModelForm(BootStrapModelForm):
    class Meta:
        model = models.Task
        fields = "__all__"
        widgets = {
            "detail": forms.TextInput      # 修改页面中详细信息插件,之前是TextField自动生成Textarea标签,不想这样生成自己定义导入form换成TextInput或者
            # "detail": forms.Textarea
        }

def task_list(request):
    """任务列表"""
    form = TaskModelForm()              # 直接在列表页面生成表单
    return render(request, 'task_list.html', {"form": form})

在这里插入图片描述
显示负责人在前端界面
在这里插入图片描述
前端页面展示表单信息

   <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">表单</div>
            <div class="panel-body">
                <form method="post" novalidate>
                    <div class="clearfix">          <!--把父级撑起来,样式的调整-->
                        {% for field in form %}
                            <div class="col-xs-6">           <!--删格6,每一个占6格-->
                                <div class="form-group">
                                    <labe><span style="font-weight:bold;">{{ field.label }}</span></labe>
                                    {{ field }}
                                </div>
                            </div>
                        {% endfor %}
                        <div class="col-xs-12">
                            <button type="submit" class="btn btn-primary">提交</button>
                        </div>
                    </div>

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

在这里插入图片描述
在这里插入图片描述
用户输入并且提交到后台(提交不能以submit提交,自己写一个button提交,再写一个Ajax请求把这些数据获取到)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
后端拿到数据做相应的校验
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

@csrf_exempt
def task_add(request):
    # print(request.POST)
    # < QueryDict: {'level': ['1'], 'title': ['中方与以色列方通话'], 'detail': ['bug'], 'user': ['2']} >

    # 1.用户发送过来的数据进行校验(ModelForm进行校验)
    # 创建一个ModelForm对象传入对象
    form = TaskModelForm(data=request.POST)
    if form.is_valid():
        form.save()
        data_dict = {"status": True}
        return HttpResponse(json.dumps(data_dict))

    # print(type(form.errors.as_json))  # 查看错误信息类型
    # # form django.forms.utils import ErrorDict
    data_dict = {"status": False, 'error': form.errors}
    return HttpResponse(json.dumps(data_dict, ensure_ascii=False))
    <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="col-xs-6">           <!--删格6,每一个占6格-->
                                <div class="form-group" style="position: relative;margin-bottom: 20px;">
                                    <!--相对的一个定位-->
                                    <labe><span style="font-weight:bold;">{{ field.label }}</span></labe>
                                    {{ field }}
                                    <span class="error-msg" style="color:red;position: absolute;"></span>
                                    <!--绝对的定位-->
                                </div>
                            </div>
                        {% endfor %}
                        <div class="col-xs-12">
                            <button id="btnAdd" type="button" class="btn btn-primary">提交</button>
                        </div>
                    </div>

                </form>
            </div>
        </div>
    <script type="text/javascript">
        $(function () {
            // 页面框架加载完成之后直接执行
            bindBtnAddEvent();
        })
        function bindBtnAddEvent() {
            $("#btnAdd").click(function () {  //绑定click事件
                $(".error-msg").empty();        // 把所有的错误信息清空
                $.ajax({
                    url: '/task/add/',   //发送的地址
                    type: "post",          //发get请求
                    data: $("#formAdd").serialize(),  //自动将表单里面的所有输入框值全部获取到并且打包后发送到Django后台
                    dataType: "JSON",
                    success: function (res) {   //登陆成功之后,自动执行success后面的函数,res是返回的值
                        if (res.status) {
                            alert("添加成功")
                        } else {
                            console.log(res.error)
                            $.each(res.error, function (name, data) {
                                console.log(name, data);
                                $("#id_" + name).next().next().text(data[0]);
                            })
                        }
                    }
                })
            })
        }
    </script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1884263.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

无法访问指向的web服务器(或虚拟主机)的目录,请检查网络设置

微信公众平台,进行业务域名、JS接口安全域名、网页授权域名配置时&#xff0c;遇到的问题中有&#xff1a;无法访问指向的web服务器&#xff08;或虚拟主机&#xff09;的目录&#xff0c;请检查网络设置&#xff0c;这里简单记录一下处理过程。 关于这个问题首先保证下载…

基于PHP技术的校园论坛设计的设计与实现08586

基于PHP技术的校园论坛设计的设计与实现 摘 要 本项目旨在基于PHP技术设计与实现一个校园论坛系统&#xff0c;以提供一个功能丰富、用户友好的交流平台。该论坛系统将包括用户注册与登录、帖子发布与回复、个人信息管理等基本功能&#xff0c;并结合社交化特点&#xff0c;增强…

2023软考中级《软件设计师》(备考冲刺版) | 数据库系统

目录 1.数据库的基本概念 1.1 数据库体系结构 1.2 三级模式结构 1.3 数据仓库 2.数据库设计过程 2.1 概念结构设计 2.1.1 概念设计过程 2.1.2 E-R图 2.2 逻辑结构设计 2.2.1 关系模式相关概念 2.2.2 E-R图转关系模式&#xff08;涉及下午题&#xff09; 2.2.3 关系…

SysML与MBSE的关系

SysML与MBSE的关系 对于任何基于模型的系统工程 &#xff08;MBSE&#xff09; 方法&#xff0c;推荐的最佳实践是基于模型的语言、基于模型的工具、基于模型的流程和基于模型的架构框架的协同应用&#xff0c;如下图所示 系统架构四元组 图。经过十年将SysML应用于棘手的系统…

海思NNIE部署yolov5-shufflenet

1.简要说明 由于NNIE上transpose支持的顺序是固定的,shufflenet那种x=torch.transpose(x,1,2).contiguous() 的操作一般是不支持的。需要进行调整。 2.使用工程以及修改 使用的是开源工程:GitHub - Lufei-github/shufflev2-yolov5: shufflev2-yolov5:lighter, faster and ea…

基于“香港世界”的SLAM技术介绍

在视觉感知技术中&#xff0c;理解和描述复杂的三维室外场景至关重要&#xff0c;尤其是自动驾驶技术的发展要求对陌生环境具有更强的适应能力和鲁棒性。传统上&#xff0c;使用“曼哈顿世界”和“亚特兰大世界”模型来描述具有垂直和水平结构的城市场景。 当遇到像香港这样地形…

python爬虫之scrapy框架基本使用

python爬虫之scrapy框架基本使用 1、环境安装&#xff1a;pip install scrapy 2、创建一个工程&#xff1a;scrapy startproject xxxPro 3、cd xxxPro 4、在spiders子目录中创建一个爬虫文件&#xff1a;scrapy genspider spiderName www.xxx.com 5、执行工程&#xff1a;scra…

当年很多跑到美加澳写代码的人现在又移回香港?什么原因?

当年很多跑到美加澳写代码的人现在又移回香港&#xff1f;什么原因&#xff1f; 近年来&#xff0c;确实有部分曾经移民到美国、加拿大、澳大利亚等地的香港居民选择移回香港。这一现象与多种因素相关&#xff0c;主要可以归结为以下几点&#xff1a; 疫情后的环境变化&#…

高通源代码版本ADK工具版本源代码release版本MDE版本介绍

0 Preface/Foreword 1 版本介绍 高通代码存放在chipcode中&#xff0c;网址URL&#xff1a;Chipcode 1.1 高通源代码版本 Bluetooth Audo芯片的高通源代码版本号&#xff08;类似于分类的类名&#xff09;&#xff1a;ADK.SRC.1.0 &#xff08;最新qcc307x系列及之后的芯片如…

如何用matplotlib绘制图像分类任务的类别特征空间分布

import matplotlib.pyplot as plt import numpy as np from sklearn.decomposition import PCA from sklearn.datasets import load_iris from mpl_toolkits.mplot3d import Axes3D# 加载示例数据&#xff08;Iris 数据集&#xff09; data load_iris() X data.data y data.…

wordpress建站有哪些优点

对于绝大多数站长来说&#xff0c;使用wordpress建站是一个非常不错的选择。那么wordpress建站有哪些优点呢&#xff1f;下面小编就来为大家解答。 1.wordpress是什么&#xff1f; WordPress是一款全球最受欢迎的内容管理系统&#xff08;CMS&#xff09;&#xff0c;主要用于…

【第11章】MyBatis-Plus条件构造器(上)

文章目录 前言一、功能详解1. allEq2. eq3. ne4. gt5. ge6. lt7. le8. between9. notBetween10. like11. notLike12. likeLeft13. likeRight14. notLikeLeft15. notLikeRight16. isNull17. in18. notIn19. inSql20. notInSql21. eqSqlSince 3.5.622. gtSql Since 3.4.3.223. ge…

LLM大模型工程师面试经验宝典--进阶版(2024.7月最新)

一、什么是生成式大模型&#xff1f; 生成式大模型&#xff08;一般简称大模型LLMs&#xff09;是指能用于创作新内容&#xff0c;例如文本、图片、音频以及视频的一类 深度学习模型。相比普通深度学习模型&#xff0c;主要有两点不同&#xff1a; 1. 模型参数量更大&#xff…

deepin基于apt-mirror同步软件源及构建本地内网源

1.安装apt-mirror sudo apt install -y apt-mirror2.配置apt-mirror(/etc/apt/mirror.list) sudo cp /etc/apt/mirror.list /etc/apt/mirror.list.deepin.bak #备份配置文件 sudo gedit /etc/apt/mirror.list修改如下&#xff1a; deb [trustedyes] https://mirrors.bfsu.ed…

KVB安全投资小知识:为什么聪明的交易员从不预测方向?

摘要&#xff1a;在金融市场中&#xff0c;聪明的交易员从不依赖预测市场方向&#xff0c;他们通过风险管理、交易策略和情绪控制等方法获得长期稳定的盈利。这篇文章详细分析了为什么聪明的交易员选择不预测市场方向&#xff0c;而是专注于其他更重要的方面&#xff0c;如风险…

Qt实现手动切换多种布局

引言 之前写了一个手动切换多个布局的程序&#xff0c;下面来记录一下。 程序运行效果如下&#xff1a; 示例 需求 通过点击程序界面上不同的布局按钮&#xff0c;使主工作区呈现出不同的页面布局&#xff0c;多个布局之间可以通过点击不同布局按钮切换。支持的最多的窗口…

HarmonyOS Next开发学习手册——文本输入 (TextInput/TextArea)

TextInput、TextArea是输入框组件&#xff0c;通常用于响应用户的输入操作&#xff0c;比如评论区的输入、聊天框的输入、表格的输入等&#xff0c;也可以结合其它组件构建功能页面&#xff0c;例如登录注册页面。具体用法请参考 TextInput 、 TextArea 。 创建输入框 TextIn…

【一篇文章带你搞懂--拉链表!!!拉链表的原理是什么!】

前言&#xff1a; &#x1f49e;&#x1f49e;大家好&#xff0c;我是书生♡&#xff0c;今天主要和大家分享一下拉链表的原理以及使用,希望对大家有所帮助。 大家可以关注我下方的链接更多优质文章供学习参考。 &#x1f49e;&#x1f49e;代码是你的画笔&#xff0c;创新是你…

怎样查看vsphere client 的登录日志

- 问题摘要&#xff1a; 怎样查看vsphere client 的登录日志 - 解决方案/工作方法 1.登录vsphere client > vc > Monitor > Tasks and Events > Events, 查看日志 2. 查看VC 的websso.log日志 /var/log/vmware/sso/websso.log 3. 可以把websso.log文件拿到本地电…

Java进阶学习|Day4.Java多线程,线程池

文章目录 了解多线程CPU进程(Process)线程多线程开发多线程优点 实现方式继承Thread类实现Runnable接口实现Callable接口 线程状态转换线程状态线程调度调整线程优先级线程睡眠线程等待线程让步线程加入线程唤醒 线程同步线程同步方式多线程间通信 线程池了解线程池定义常见接口…