首页 > 其他分享 >探秘 Django 专业之道

探秘 Django 专业之道

时间:2024-07-01 21:59:38浏览次数:3  
标签:form models self py request Django 之道 探秘 page

一、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>

标签:form,models,self,py,request,Django,之道,探秘,page
From: https://blog.csdn.net/m0_69402477/article/details/140110403

相关文章

  • 【算法探秘】无重复字符的最长子串:解锁字符串中的独特风景
    【算法探秘】无重复字符的最长子串:解锁字符串中的独特风景一、引言:在字符的海洋中航行二、技术概述:独步字符森林技术定义核心特性代码示例:初尝甜蜜果实三、技术细节:拨开迷雾,洞悉本质原理解析难点剖析四、实战应用:字节跳跃,解密信息应用场景案例展示五、优化与改进:精益......
  • 数据的净化之道:SQL Server DQS的数据清洗艺术
    数据的净化之道:SQLServerDQS的数据清洗艺术在信息时代,数据的价值不言而喻,但数据质量问题却常常成为企业决策的绊脚石。SQLServer的DataQualityServices(DQS)提供了一套强大的数据清洗工具,帮助企业提升数据质量,确保数据分析的准确性。本文将深入探讨DQS如何助力数据清......
  • 【产品经理修炼之道】-AI时代的产品经理?
    伴随着AI人工智能技术的快速发展,产品经理这一角色也或多或少会被这一浪潮所影响。那么,AI时代还需要产品经理吗?或许在智能涌现的时代,产品经理需要思考,怎样才可以在AI2.0时代找到自己的立足点和核心竞争力。一起来看看本文的讲述。在被ChatGPT和大模型裹挟着踏入AGI时代后,产品......
  • 探秘数据库中的并行计算技术应用
    本文分享自华为云社区《【GaussTech技术专栏】数据库中并行计算技术应用探秘》,作者:GaussDB数据库。并行计算是提高系统性能的重要手段之一。该技术是通过利用多台服务器、多个处理器、处理器中的多核以及SIMD指令集等技术,实现任务的并行化处理,从而加快任务处理的速度。同时,在多个......
  • Django数据库
    一、MySQL驱动程序安装我们使用Django来操作MySQL,实际上底层还是通过python来操作的。因此我们想要用Django来操作MySQL,首先还是需要安装一个驱动程序。在Python3中,驱动程序有多种选择。比如pymysql以及mysqlclient等。这里我们就使用mysqlclient来操作。mysqlclient安装非常简单......
  • 基于Python+Django的商城购物系统设计与实现(源码+数据库+讲解)
    文章目录前言详细视频演示项目运行截图技术框架后端采用Django框架前端框架Vue可行性分析系统测试系统测试的目的系统功能测试数据库表设计代码参考数据库脚本为什么选择我?获取源码前言......
  • Django 笔记 - Django Shell
    启动DjangoShell交互式界面,具体命令如下:pythonmanage.pyshell具体实例实例1.直接修改用户密码,无需原密码。在DjangoShell交互式界面下,修改admin用户密码的具体代码如下:fromdjango.contrib.auth.modelsimportUseruser=User.objects.get(username='admin'......
  • 库分表后复杂查询的应对之道:基于DTS实时性ES宽表构建技术实践
    1问题域业务发展的初期,我们的数据库架构往往是单库单表,外加读写分离来快速的支撑业务,随着用户量和订单量的增加,数据库的计算和存储往往会成为我们系统的瓶颈,业界的实践多数采用分而治之的思想:分库分表,通过分库分表应对存系统读写性能瓶颈和存储瓶颈;分库分表帮我们解决问题的同时......
  • 《代码整洁之道》精华速览,助你提升代码质量
    最近重读了一遍《代码整洁之道》,这本书既是整洁代码的定义,也是写出整洁代码的指南。我认为既适合新手阅读,快速提升代码质量;也适合老鸟阅读,持续精进。本篇将汇总《代码整洁之道》的必读要点,把书读薄,方便各位快速阅读。为什么要阅读《代码整洁之道》第一,是个程序员;第二,想成为更好......
  • Web前端工程师修炼之道
    书籍介绍 你是否也曾想过自己创建网页,但却苦于没有经验?那么从现在开始学习吧!本书由浅入深地讲解了Web设计的一些重要概念、基本原理,以及HTML、CSS和JavaScript的具体使用方法与技巧。当你读完本书后,将会掌握创建适用于移动设备的多列页面的技巧。 《Web前端工程师修炼之......