探秘 Django 专业之道

一、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_serverdef 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 Responsedef application(environ, start_response):response = Response('Hello World!', mimetype='text/plain')return response(environ, start_response)if __name__ == '__main__':from werkzeug.serving import run_simplerun_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 pathfrom django.shortcuts import HttpResponsedef 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.venvday002......manage.pyappswebbackendapi

先在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 modelsclass 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_iddepart = 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 = UserInfofields = ["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=Trueprice = 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 formsclass 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)  # 小于等于12data_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")     # 筛选出包含999data_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_safeclass 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 QueryDictimport copyquery_dict = copy.deepcopy(request.GET)query_dict._mutable = Trueself.query_dict = query_dictself.page_param = page_parampage = request.GET.get(page_param, "1")if page.isdecimal():page = int(page)else:page = 1self.page = pageself.page_size = page_sizeself.start = (page - 1) * page_sizeself.end = page * page_sizeself.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 += 1self.total_page_count = total_page_countself.plus = plusdef html(self):# 计算出,显示当前页的前5页、后5页if self.total_page_count <= 2 * self.plus + 1:# 数据库中的数据比较少,都没有达到11页。start_page = 1end_page = self.total_page_countelse:# 数据库中的数据比较多 > 11页。# 当前页<5时(小极值)if self.page <= self.plus:start_page = 1end_page = 2 * self.plus + 1else:# 当前页 > 5# 当前页+5 > 总页面if (self.page + self.plus) > self.total_page_count:start_page = self.total_page_count - 2 * self.plusend_page = self.total_page_countelse:start_page = self.page - self.plusend_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.UserInfofields = ["name", "password",]form = UserModelForm()
在HTML中只是生成了普通的input框没有bootstrap样式:
{{form.name}}      普通的input框
{{form.password}}  普通的input框
  • 定义插件
class UserModelForm(forms.ModelForm):class Meta:model = models.UserInfofields = ["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.UserInfofields = ["name", "password", "age"]
在HTML展示是可以有bootstrap样式的
{{form.name}}      BootStrap的input框
{{form.password}}  BootStrap的input框
问题在于这么写太繁琐了,所有我们重新定义init方法
  • 重新定义的init方法,批量设置
class UserModelForm(forms.ModelForm):class Meta:model = models.UserInfofields = ["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.UserInfofields = ["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.labelelse: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.labelelse:field.widget.attrs = {"class": "form-control", "placeholder": field.label}
让它继承:
class UserEditModelForm(BootStrapModelForm):class Meta:model = models.UserInfofields = ["name", "password", "age",]
1.9.1 操作
  • 提取公共的类
    在这里插入图片描述
  • vews.py中找到所有的modelform继承并拆分出来
    在这里插入图片描述
  • vews.py文件中的业务按照类型拆分斌删除vews.py文件
    在这里插入图片描述
  • 关键点:修改urls.py文件
    在这里插入图片描述

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

1. 管理员操作

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

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

1.1 添加

from django.shortcuts import render, redirectfrom app01 import models
from app01.utils.pagination import Paginationfrom django import forms
from django.core.exceptions import ValidationError
from app01.utils.bootstrap import BootStrapModelForm
from app01.utils.encrypt import md5class AdminModelForm(BootStrapModelForm):confirm_password = forms.CharField(label="确认密码",widget=forms.PasswordInput(render_value=True))class Meta:model = models.Adminfields = ["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 confirmdef 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.Adminfields = ['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_pwddef 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):""" 重置密码 """# 对象 / Nonerow_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 modelsclass 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 HttpResponseclass M1(MiddlewareMixin):""" 中间件1 """def process_request(self, request):# 如果方法中没有返回值(返回None),继续向后走# 如果有返回值 HttpResponse、render 、redirectprint("M1.process_request")return HttpResponse("无权访问")def process_response(self, request, response):print("M1.process_response")return responseclass 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, redirectclass 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 randomdef 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, ImageFilterdef check_code(width=120, height=30, char_length=5, font_file='Monaco.ttf', font_size=28):  # 字体文件:Monaco.ttfcode = []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_strprint(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, ImageFilterdef check_code(width=120, height=30, char_length=5, font_file='Monaco.ttf', font_size=28):  # 字体文件:Monaco.ttfcode = []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 jsonfrom django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exemptdef 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.Taskfields = "__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 ErrorDictdata_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.mzph.cn/pingmian/38849.shtml

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

相关文章

Linux下SUID提权学习 - 从原理到使用

目录 1. 文件权限介绍1.1 suid权限1.2 sgid权限1.3 sticky权限 2. SUID权限3. 设置SUID权限4. SUID提权原理5. SUID提权步骤6. 常用指令的提权方法6.1 nmap6.2 find6.3 vim6.4 bash6.5 less6.6 more6.7 其他命令的提权方法 1. 文件权限介绍 linux的文件有普通权限和特殊权限&a…

计算机毕业设计Python深度学习美食推荐系统 美食可视化 美食数据分析大屏 美食爬虫 美团爬虫 机器学习 大数据毕业设计 Django Vue.js

Python美食推荐系统开题报告 一、项目背景与意义 随着互联网和移动技术的飞速发展&#xff0c;人们的生活方式发生了巨大变化&#xff0c;尤其是餐饮行业。在线美食平台如雨后春笋般涌现&#xff0c;为用户提供了丰富的美食选择。然而&#xff0c;如何在海量的餐饮信息中快速…

(1)Jupyter Notebook 下载及安装

目录 1. Jupyter Notebook是什么&#xff1f;2. Jupyter Notebook特征3. 应用3. 利用Google Colab安装Jupyter Notebook3.1 什么是 Colab&#xff1f;3.2 访问 Google Colab 1. Jupyter Notebook是什么&#xff1f; 百度百科: Jupyter Notebook&#xff08;此前被称为 IPython …

Unity Shader 软粒子

Unity Shader 软粒子 前言项目Shader连连看项目渲染管线设置 鸣谢 前言 当场景有点单调的时候&#xff0c;就需要一些粒子点缀&#xff0c;此时软粒子就可以发挥作用了。 使用软粒子与未使用软粒子对比图 项目 Shader连连看 这里插播一点&#xff0c;可以用Vertex Color与…

ARP 原理详解 二

只要确定了 IP 地址后&#xff0c;就能够向这个 IP 地址所在的主机发送数据报&#xff0c;这是我们所熟知的事情。 但是再往深了想&#xff0c;IP 地址只是标识网络层的地址&#xff0c;那么在网络层下方数据链路层是不是也有一个地址能够告诉对方主机自己的地址呢&#xff1f…

生产环境部署与协同开发-Docker(原创超全)

关闭防火墙 systemctl stop firewalld.service 关闭SELinux vim /etc/selinux/config 查看yum支持的包并安装docker引擎 yum listyum install -y docker 启动docker设置docker自启动测试docker是否安装成功&#xff1f; systemctl start dockersystemctl enable dockerdoc…

算法基础-----【动态规划】

动态规划(待完善) 动规五部曲分别为&#xff1a; 确定dp数组&#xff08;dp table&#xff09;以及下标的含义确定递推公式&#xff08;状态转移公式&#xff09;dp数组如何初始化确定遍历顺序举例推导dp数组、 动态规划的核心就是递归剪枝&#xff08;存储键值&#xff0c;…

教师备课三要素是指什么内容

在教育的舞台上&#xff0c;教师的角色至关重要。他们不仅是知识的传递者&#xff0c;更是学生学习路上的引导者。那么&#xff0c;教师备课的三要素究竟是什么呢&#xff1f;这不仅是每个教师在教学过程中必须面对的问题&#xff0c;也是他们不断探索和实践的课题。 教师备课的…

如何通过TPM活动提升员工的设备管理能力?

在快节奏的现代职场中&#xff0c;设备管理能力已成为员工综合素质的重要一环。然而&#xff0c;如何有效提升这一能力&#xff0c;让员工在设备操作、维护和管理上更加得心应手呢&#xff1f;答案就隐藏在TPM&#xff08;Total Productive Maintenance&#xff0c;全面生产维护…

Python容器 之 列表--定义

1.什么是列表呢&#xff1f; 列表(list)是 Python 中使用最频繁的数据类型, 在其他语言中通常叫做数组, 专门用来存储一组数据 列表,list, 使用 [ ] 列表可以存放任意多个数据 列表中可以存放任意类型的数据 列表中数据之间 使用 逗号隔开 2.列表如何定义&#xff1f; &#…

【TB作品】atmega16 计算器,ATMEGA16单片机,Proteus仿真

实验报告&#xff1a;基于ATmega16单片机的简易计算器设计 1. 实验背景 计算器是日常生活和工作中不可或缺的工具&#xff0c;通过按键输入即可实现基本的四则运算。通过本实验&#xff0c;我们将利用ATmega16单片机、矩阵键盘和LCD1602显示屏&#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 关系…

小白学习手册:轻松理解MQ消息队列

目录 # 开篇 RabbitMQ介绍 通讯概念 1. 初始MQ及类型 2. MQ的架构 2.1 RabbitMQ的结构和概念 2.2 RabbitMQ消息流示意图 3. MQ下载使用 3.1 Docker下载MQ参考 3.2 进入RabbitMQ # 开篇 MessagesQueue 是一个抽象概念&#xff0c;用于描述消息队列系统的一般特性和功能…

python如何求不定积分

sympy介绍 sympy库的安装非常的简单&#xff0c;利用conda命令可以快速的完成安装。 conda install sympy 接下来&#xff0c;我们将介绍利用第三方库sympy来完成积分的计算。 python求解不定积分 接下来&#xff0c;我们将介绍上述的不定积分的求解。 首先导入sympy库中的…

大聪明教你学Java | 深入浅出聊 RocketMQ

前言 &#x1f34a;作者简介&#xff1a; 不肯过江东丶&#xff0c;一个来自二线城市的程序员&#xff0c;致力于用“猥琐”办法解决繁琐问题&#xff0c;让复杂的问题变得通俗易懂。 &#x1f34a;支持作者&#xff1a; 点赞&#x1f44d;、关注&#x1f496;、留言&#x1f4…

YOLOv10改进教程|C2f-CIB加入注意力机制

一、 导读 论文链接&#xff1a;https://arxiv.org/abs/2311.11587 代码链接&#xff1a;GitHub - CV-ZhangXin/AKConv YOLOv10训练、验证及推理教程 二、 C2f-CIB加入注意力机制 2.1 复制代码 打开ultralytics->nn->modules->block.py文件&#xff0c;复制SE注意力机…

Docker期末复习

云计算服务类型有: IaaS 基础设施及服务 PaaS 平台及服务 SaaS 软件及服务 服务类型辨析示例: IaaS 服务提供的云服务器软件到操作系统,具体应用软件自己安装,如腾讯云上申请的云服务器等;SaaS提供的服务就是具体的软件,例如微软的Office套件等。 云计算部署模式有: 私有云…

发那科机床采集数据

前面两篇重点介绍了理论&#xff0c;从这篇开始&#xff0c;我们开始进行实战。首先从发那科机床开始&#xff0c;为何第一个将发那科。因为发那科系统机床有三最。最广泛&#xff08;中国保有量最多&#xff09;、 最多资料&#xff08;发那科系统的开发包历史悠久&#xff0c…

Linux——移动文件或目录,查找文件,which命令

移动文件或目录 作用 - mv命令用于剪切或重命名文件 格式 bash mv [选项] 源文件名称 目标文件名称 注意 - 剪切操作不同于复制操作&#xff0c;因为它会把源文件删除掉&#xff0c;只保留剪切后的文件。 - 如果在同一个目录中将某个文件剪切后还粘贴到当前目录下&#xff0c;…

CS144 Lab3 TCPSender复盘

一.基础概念 1.TCPSender在TCPSocket中的地位与作用 Lab0中实现了基于内存模拟的流控制-字节流&#xff08;ByteStream&#xff09;&#xff0c;底层使用std::deque实现&#xff0c;根据最大容量Capacity进行容量控制。个人理解它相当于应用层的输入输出缓存区&#xff0c;用户…