文章目录
- Django学习
- 1、项目创建
- 2、默认项目介绍
- 3、app的创建和说明
- 4、启动运行Django
- 4.1**确保app已注册**
- 4.2 **编写URL和视图函数的对应关系【urls.py】**
- 4.3**编写视图函数【views.py】**
- 4.4**启动Django项目**
- 4.5、templates模板
- 4.6、静态文件
- 5、模板语法
- **案例:伪联通新闻中心**
- 6、请求和响应
- 案例:用户登录
- 7、数据库操作
- 7.1、安装mysqlclient
- 7.2、orm创建数据库
- 1、创建数据库
- 2、Django连接数据库
- 3、Django操作表
- 3.1、创建表
- 3.2、执行命令
- 3.3、操作表中的数据
- 案例:用户管理
- 1.、展示用户列表
- 2、添加用户
- 3、删除用户
- 8、员工管理系统
- 8.1、创建项目
- 8.2、创建app,终端运行 **python manage.py startapp xxx**
- 8.3、注册app
- 8.4、设计表结构
- 8.5、配置数据库
- 8.6、生成表
- 8.7、创建静态文件和模板文件
- 8.8、部门管理
- 8.8.1、urls
- 8.8.2、views
- 9、html继承
- 10、用户管理
- 10.2、用户列表
- 10.3、添加用户
- 10.3.1、初识Form
- 1、views.py
- 2、user_add.html
- 10.3.2、ModelForm(最简便)
- 1、models.py
- 2、views.py
- 10.3.3、添加用户
- 1、views.py
- 2、html
- 10.4、编辑用户
- 11、总结-1
- 12、 靓号管理
- 搜索
- 分页
- 13、管理员操作
- 14、用户登录
- 14.1、session登录
- 14.2、Django的中间件
- 14.3、编写登录中间件
- 14.4、注销
- 14.5、模板登录信息
- 14.5、图片验证码
- 5.1、生成图片
- 5.2、函数
- 5.3、urls路径
- 5.4、视图
- 5.5、前端
- 14.6、完整的登录
- 6.1 urls
- 6.2 视图
- 6.3、页面
- 15、Ajax
- 15.1、get请求
- 15.2、post请求
- 15.3、关闭绑定事件
- 15.4、Ajax请求的返回值
- 16、订单
- html
- 视图
- 17、文件上传
- 17.1、基本操作
- 17.2、Excel批量上传
- 17.3、混合数据(form)
- 17.4、启用media,存数据
- 17.5、混合数据(ModelForm)
- Django 函数+知识点
- 分页 --类
- bootstrap样式-父类
- 封装
- md5加密
- 数据库中获取数据
- 柱状图
- 总结
Django学习
1、项目创建
pycharm:
- 新建项目
- 删除templates
- 删除settings里的。。为了不在根目录寻找而是创建的目录下寻找templates目录
- 修改__ init __.py
import pymysql
pymysql.install_as_MySQLdb()
2、默认项目介绍
djangostudy
manage.py 【项目的管理,启动项目、创建app、数据管理】【不要动】
djangostudy
__init__.py
settings.py 【项目配置】 【**常常操作**】
urls.py 【url和函数的对应关系】【**常常操作**】
asgi.py 【接收网络请求】【不要动】
wsgi.py 【接收网络请求】【不要动】
3、app的创建和说明
说明
-项目
-app,用户管理【表结构、函数、html模板、css】
-app,订单管理【表结构、函数、html模板、css】
-app,后台管理【表结构、函数、html模板、css】
-app,网站【表结构、函数、html模板、css】
-app,api【表结构、函数、html模板、css】
。。。
创建:
app01
__init__.py
admin.py 【固定,不用动】Django默认提供了admin后台管理
apps.py 【固定,不用动】app启动类
migrations 【固定,不用动】数据库变更记录
__init__.py
models.py 【**重要**】对数据库操作
tests.py 【固定,不用动】单元测试
views.py 【**重要**】,函数
4、启动运行Django
4.1确保app已注册
4.2 编写URL和视图函数的对应关系【urls.py】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z8jJ9pAL-1654077355201)(https://gitee.com/cool-dada/blog_img/raw/master/tree/master/img_markdown/202206011745585.png)]
4.3编写视图函数【views.py】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iR3AT8Nb-1654077355201)(https://gitee.com/cool-dada/blog_img/raw/master/tree/master/img_markdown/202206011745336.png)]
4.4启动Django项目
4.5、templates模板
4.6、静态文件
在开发过程中一般将 图片、css、js都会当做静态文件处理
static文件夹下存放静态文件
- plugins:用于存放插件
插件使用+引入
{% static ‘路径’ %}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XXMKjNKJ-1654077355204)(https://gitee.com/cool-dada/blog_img/raw/master/tree/master/img_markdown/202206011746076.png)]
5、模板语法
本质上:在html中写一些占位符,由数据对这些占位符进行替换和处理。
views
def tpl(request):
name = '李锦彪'
roles = ['李锦彪', '黄欣宇', '锦欣宇'] # 列表
user_info = {'name': '李锦彪', 'salary': 26000, 'role': 'ceo'} # 字典
data_list = [ # 列表里套字典
{'name': '李锦彪', 'salary': 26000, 'role': 'ceo'},
{'name': '李锦彪', 'salary': 26000, 'role': 'ceo'},
{'name': '李锦彪', 'salary': 26000, 'role': 'ceo'}
]
return render(request,
'tpl.html', # 传入html
{ # 传入一个字典,html通过{{ key }}获取value
'n1': name,
'n2': roles,
'n3': user_info,
'n4': data_list,
}
)
html
{# 获取传入的值 #}
<p>{{ n1 }}</p>
============================================
{# 获取传入的列表值 #}
{# 一个一个拿 #}
<p>{{ n2.0 }}</p>
<p>{{ n2.1 }}</p>
<p>{{ n2.2 }}</p>
{# 循环拿 #}
<div>
{% for item in n2 %}
<p>{{ item }}</p>
{% endfor %}
</div>
<hr/> {# 加条线 #}
==============================================
{# 获取字典的值 #}
{{ n3 }}
{# 根据字典的键获取值 #}
{{ n3.name }}
{{ n3.salary }}
{{ n3.role }}
{# 循环获取 #}
<div>
{# 第一种 #}
{# {% for item in n3 %}#}
{# <li>{{ item }}</li>#}
{# {% endfor %}#}
{# 第二种 #}
{% for k, v in n3.items %}
<li>{{ k }}={{ v }}</li>
{% endfor %}
</div>
<hr>
===============================================
{% if n1 == '李锦彪' %}
<h1>哈哈哈哈</h1>
{% else %}
<h1>黑恶hi诶嘿二哈IE</h1>
{% endif %}
视图函数的render内部:
- 读取含有模板语法的html文件
- 内部进行渲染(模板语法执行并替换数据),最终得到只包含html标签的字符串
- 将渲染(替换)完成的字符串返还给用户浏览器
案例:伪联通新闻中心
**第一步:**urls.py中创建路径
第二步:views.py中创建函数news
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tvSZ7kfc-1654077355206)(https://gitee.com/cool-dada/blog_img/raw/master/tree/master/img_markdown/202206011746481.png)]
第三步:编写html文件
<h1>联通新闻中心</h1>
<ul>
{% for item in news_list %}
<li>{{ item.news_title }}</li>
{% endfor %}
</ul>
6、请求和响应
关于重定向:当前的页面请求访问其他的页面。其他的页面不同意并且会返回一个值,告诉当前的页面去访问这个值
# request 是一个对象,封装了用户发送过来的所有请求相关数据
# 1.【请求】获取请求方式 get/post
print(request.method)
# 2.【请求】在URL上传递值 http://127.0.0.1:8000/something/?n=100
print(request.GET) # 拿到传递的值
# 3.【请求】post请求,在请求体中传递数据
print(request.POST)
# 4.【响应】HttpResponse('返回内容'),内容字符串返回给请求者
# return HttpResponse('返回内容')
# 5.【响应】读取html内容 + 渲染(替换) -> 字符串,返回内容给用户浏览器
# return render(request, 'something.html', {'title': '李锦彪'})
# 6.【响应】让浏览器重定向到其他的页面redirect('https://www.baidu.com')
return redirect('https://www.baidu.com')
案例:用户登录
问题:安全机制校验
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cKuj760e-1654077355207)(https://gitee.com/cool-dada/blog_img/raw/master/tree/master/img_markdown/202206011752654.png)]
解决办法:form表单里加 {% csrf_token %}
第一步:views.py
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
# 如果是post请求,获取用户提交的数据
# print(request.POST)
usr = request.POST.get('username')
pwd = request.POST.get('password')
if usr == '15751083927' and pwd == '123':
# return HttpResponse('登录成功')
return redirect('https://www.baidu.com') # 登录成功重定向跳转页面
else:
# return HttpResponse('登录失败')
return render(request, 'login.html', {'error_msg': '登录失败'})
第二步:html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>用户登录</h1>
<form action="/login/" method="post">
{% csrf_token %}
<input type="text" name="username" placeholder="用户名">
<input type="password" name="password" placeholder="密码">
<input type="submit">
<span style="color: red">{{ error_msg }}</span>
</form>
</body>
</html>
7、数据库操作
Django开发操作数据库,内部提供了orm框架
7.1、安装mysqlclient
7.2、orm创建数据库
orm可以帮助我们做两件事:
- 创建、修改、删除数据库中的表(不用写SQL语句)(无法创建数据库)
- 操作表中的数据(不用写SQL语句)
1、创建数据库
- 启动数据库
- 自带工具创建数据库
2、Django连接数据库
在setting.py文件中,进行配置和修改
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'ljb', # 数据库名字
'USER': 'root', # 账号
'PASSWORD': '187365', # 密码
'HOST': '127.0.0.1', # 主机
'PORT': 3306, # 端口号
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-18oVfvWK-1654077355208)(https://gitee.com/cool-dada/blog_img/raw/master/tree/master/img_markdown/202206011746040.png)]
3、Django操作表
- 创建表
- 修改表
- 删除表
3.1、创建表
在models.py文件中
# 创建表
class Userinfo(models.Model):
name = models.CharField(max_length=32) # varchar(32)
password = models.CharField(max_length=64)
age = models.IntegerField() # int 类型
==相当于
# create table app01_userinfo( # 表明为:app01+类名首字母小写
# id bigint auto_increment primary key , # Django自动加这一行
# name varchar(32),
# password varchar(64),
# age int
# );
3.2、执行命令
在终端执行:
python manage.py makemigrations
python manage.py migrate
注意:app先注册(settings)
新增列的时候,由于已经在列中可能已有数据,所以新增列必须要指定新增列对应的数据
- 手动输入一个值
- 设置默认值
age = models.IntegerField(default=2)
- 允许为空
age = models.IntegerField(null=True, blank=True)
以后在开发中如果想要操作对表结构进行调整
- 在models.py文件中操作即可
- 在终端执行命令
python manage.py makemigrations
python manage.py migrate
3.3、操作表中的数据
在views.py中
def orm(request):
from app01 import models # 导入models文件
# 测试orm表操作表中的数据
# #########新建表数据##########
# models.Userinfo.objects.create(name='李锦彪', password='187365', age=18)
# models.Userinfo.objects.create(name='黄欣宇', password='187365', age=18)
# models.Userinfo.objects.create(name='锦欣宇', password='187365', age=18)
# ############删除表数据#############
# 先筛选 filter(xx=xx)
# 再删除 delete()
# models.Userinfo.objects.filter(name='李锦彪').delete()
# all全部删除
# models.Userinfo.objects.all()
# ############获取表数据#############
# data_list = [行,行。。。] QuerySet类型的数据
# 拿到所有数据#############
# data_list = models.Userinfo.objects.all()
# print(data_list)
# for obj in data_list:
# print(obj.name, obj.password, obj.age)
# 筛选数据#############
# data_row = models.Userinfo.objects.filter(name='黄欣宇')[0] # [0]可以改为.first()
# print(data_row.name, data_row.password, data_row.age)
# ############更新表数据#############
models.Userinfo.objects.filter(name='黄欣宇').update(age=28)
return HttpResponse('成功!')
案例:用户管理
1.、展示用户列表
- url
- 函数
- 获取所有用户的信息
- html渲染
def info_list(request):
# 1.获取数据库中所有用户的信息
from app01.models import Userinfo
data_list = Userinfo.objects.all()
print(data_list)
# 2.渲染获取到数据
return render(request, 'info_list.html', {'data_list': data_list})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>info_list</h1>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
</tr>
</thead>
<tbody>
{% for obj in data_list %}
<tr>
<td>{{ obj.id }}</td>
<td>{{ obj.name }}</td>
<td>{{ obj.password }}</td>
<td>{{ obj.age }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
2、添加用户
- url
- 函数
- get ,看到页面,输入内容
- post,提交->写入到数据库
def info_add(request):
if request.method == "GET":
return render(request, 'info_add.html')
# 获取用户提交的数据
user = request.POST.get("user")
pwd = request.POST.get("pwd")
age = request.POST.get("age")
# 加入到数据库
from app01.models import Userinfo
Userinfo.objects.create(name=user, password=pwd, age=age)
# 自动跳转
return redirect('/info/list')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>添加用户</h1>
<form action="" method="post">
{% csrf_token %}
<input type="text" name="user" placeholder="用户名">
<input type="password" name="pwd" placeholder="密码">
<input type="text" name="age" placeholder="年龄">
<input type="submit">
</form>
</body>
</html>
3、删除用户
- url
- 函数
def info_delete(request):
nid = request.GET.get('nid')
from app01.models import Userinfo
Userinfo.objects.filter(id=nid).delete()
return redirect('/info/list')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>info_list</h1>
<a href="/info/add">添加</a>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for obj in data_list %}
<tr>
<td>{{ obj.id }}</td>
<td>{{ obj.name }}</td>
<td>{{ obj.password }}</td>
<td>{{ obj.age }}</td>
<td><a href="/info/delete/?nid={{ obj.id }}">删除</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
8、员工管理系统
8.1、创建项目
删除templates文件夹,删除
8.2、创建app,终端运行 python manage.py startapp xxx
8.3、注册app
8.4、设计表结构
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='密码')
sex_choice = (
(True, '男'),
(False, '女')
)
sex = models.BooleanField(verbose_name='性别', choices=sex_choice)
account = models.DecimalField(verbose_name='账户余额', max_digits=10, decimal_places=2, default=0)
create_time = models.DateTimeField(verbose_name='入职时间')
# title_id = models.BigIntegerField(verbose_name='部门ID') 无约束
# 1.有约束(外键)
# to:与哪张表关联
# to_field:表中的某一列关联
# 生成列;depart_id
# depart = models.ForeignKey(to="Department", to_field="id")
# 2.部门表被删除
# 2.1 级联删除
# depart = models.ForeignKey(to="Department", to_field="id", on_delete=models.CASCADE)
# 2.2 置空
depart = models.ForeignKey(verbose_name='部门', to="Department", to_field="id",
null=True, blank=True, on_delete=models.CASCADE)
8.5、配置数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'ljb', # 数据库名字
'USER': 'root', # 账号
'PASSWORD': '187365', # 密码
'HOST': '127.0.0.1', # 主机
'PORT': 3306, # 端口号
}
}
8.6、生成表
python manage.py makemigrations
python manage.py migrate
注意:
报错:
解决:
原因:PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中则使用mysqldb。
MySQLdb并不支持Python3.
8.7、创建静态文件和模板文件
8.8、部门管理
8.8.1、urls
urlpatterns = [
# path('admin/', admin.site.urls),
path('depart/list/', views.depart_list),
path('depart/delete/', views.depart_delete),
# http://127.0.0.1:8000/depart/12/edit/
# http://127.0.0.1:8000/depart/1/edit/
# http://127.0.0.1:8000/depart/16/edit/
path('depart/<int:nid>/edit/', views.depart_edit),
]
8.8.2、views
重定向:要引入 redirect
from django.shortcuts import render, redirect
from Employee import models
def depart_list(request):
if request.method == "GET":
# 1.去数据库中获得所有的列表
data_list = models.Department.objects.all()
return render(request, 'depart_list.html', {'data_list': data_list})
# 2.添加部门
# 获取对象
data_department = request.POST.get('department')
# 添加对象
models.Department.objects.create(title=data_department)
# 重定向
return redirect('/depart/list/')
def depart_delete(request):
"""删除部门"""
# 获取id
# http://127.0.0.1:8000/depart/delete/?nid=1
nid = request.GET.get('nid')
# 删除id
models.Department.objects.filter(id=nid).delete()
# 重定向返回部门列表
return redirect('/depart/list/')
def depart_edit(request, nid):
"""编辑部门"""
if request.method == "GET":
row_data = models.Department.objects.filter(id=nid).first()
return render(request, 'depart_edit.html', {'row_data': row_data})
# 获取表单内容
title = request.POST.get('department')
# 根据id更新
models.Department.objects.filter(id=nid).update(title=title)
return redirect('/depart/list/')
9、html继承
- 可以有多个block
母版:
{% 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-dist/css/bootstrap.css' %}">
{% block css %}{% endblock %}
</head>
<body>
<div>
<div class="container">
{% block content %}{% endblock %}
</div>
</div>
</body>
<script src="{% static 'js/jquery-3.6.0.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1-dist/js/bootstrap.js' %}"></script>
{% block js %}{% endblock %}
</html>
继承母版:
{% extends 'layout.html' %}
{% block css %}
{% endblock %}
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1-dist/css/bootstrap.css' %}">
<body>
{% block content %}
{% endblock %}
</body>
<script src="{% static 'js/jquery-3.6.0.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1-dist/js/bootstrap.js' %}"></script>
{% block js %}
{% endblock %}
10、用户管理
Django中对于一些选项的元组存元组形式获取元组中的值:对象.get_属性_display()
例:
sex_choice = (
(0, '男'),
(1, '女')
)
sex = models.SmallIntegerField(verbose_name='性别', choices=sex_choice)
取法:
obj.get_sex_display()
html中
外键获取另一个表的值
{% for obj in user_lists %}
<tr>
<td>{{ obj.id }}</td>
<td>{{ obj.name }}</td>
<td>{{ obj.password }}</td>
<td>{{ obj.get_sex_display }}</td>
<td>{{ obj.age }}</td>
<td>{{ obj.depart.title }}</td> # 外键获取另一个表的值
<td>{{ obj.account }}</td>
<td>{{ obj.create_time }}</td>
</tr>
{% endfor %}
10.2、用户列表
时间输出格式
{% for obj in user_lists %}
<tr>
<td>{{ obj.id }}</td>
<td>{{ obj.name }}</td>
<td>{{ obj.password }}</td>
<td>{{ obj.get_sex_display }}</td>
<td>{{ obj.age }}</td>
<td>{{ obj.depart.title }}</td>
<td>{{ obj.account }}</td>
<td>{{ obj.create_time|date:"Y-m-d" }}</td> # 时间输出格式
<td>
{# 编辑#}
<a href="/user/{{ obj.id }}/edit/" class="btn btn-primary btn-xs">
<span class="glyphicon glyphicon-cog"></span>
</a>
{# 删除#}
<a href="/user/delete/?nid={{ obj.id }}" class="btn btn-danger btn-xs">
<span class="glyphicon glyphicon-trash"></span>
</a>
</td>
</tr>
{% endfor %}
10.3、添加用户
- 原始方式思路:不会采用(本质)【麻烦】
- 用户提交数据没有校验
- 错误,页面应该有提示
- 页面上每一个字段都需要重新写
- 关联的数据,手动去获取并展示在页面
- Django组件
- Form组件(小简便)
- ModelForm组件(最简便)
10.3.1、初识Form
1、views.py
class MyForm(Form):
user = forms.CharFiled(widget=forms.Input)
pwd = forms.CharFiled(widget=forms.Input)
email = forms.CharFiled(widget=forms.Input)
def user_list(request):
if request.method == "GET":
form = MyForm() # 实例化
return render(request, 'user_list.html', {'form': form})
2、user_add.html
<form method="post">
{{form.user}} # 自动生成html input标签
{{form.pwd}}
{{form.email}}
# <input type="text" class="form-control" name="name" placeholder="姓名">
</form>
或:
<form method="post">
{% for field in form %}
{{ field }}
{% endfor %}
</form>
10.3.2、ModelForm(最简便)
1、models.py
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='密码')
sex_choice = (
(0, '男'),
(1, '女')
)
sex = models.SmallIntegerField(verbose_name='性别', choices=sex_choice)
account = models.DecimalField(verbose_name='账户余额', max_digits=10, decimal_places=2, default=0)
create_time = models.DateField(verbose_name='入职时间')
# 2.1 级联删除
depart = models.ForeignKey(to="Department", to_field="id", on_delete=models.CASCADE)
2、views.py
class MyForm(ModelForm):
class Meta:
model = UserInfo
fields = ["name", "password", "age"]
def user_list(request):
if request.method == "GET":
form = MyForm() # 实例化
return render(request, 'user_list.html', {'form': form})
10.3.3、添加用户
1、views.py
# ################################### ModelForm 实例 ###############
from django import forms
class UserModelForm(forms.ModelForm):
# 添加其他的判断
name = forms.CharField(min_length=2, max_length=12, label="用户名")
class Meta:
model = models.Userinfo
fields = ["name", "password", "age", "sex", "account", "depart", "create_time"] # 添加表中的字段
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) # 继承
# 循环找到所有,添加样式
for name, field in self.fields.items():
field.widget.attrs = {"class": "form-control", "placeholder": field.label}
def user_add(request):
"""添加用户 ModelForm版本"""
if request.method == "GET":
form = UserModelForm() # 实例化一个对象
return render(request, 'user_modelform.html', {"form": form})
# 用户 post 提交数据,数据校验
form = UserModelForm(data=request.POST)
if form.is_valid(): # 判断数据是否合法
# 如果数据合法,提交数据
form.save() # 自动保存,定义哪个,保存哪个
return redirect('/user/list/')
# 校验失败(在页面上提示信息)
return render(request, 'user_modelform.html', {"form": form})
2、html
<form method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label>{{ field.label }}</label>
{{ field }}
<span style="color: red">{{ field.errors.0 }}</span>
</div>
{% endfor %}
{# 提交 #}
<button type="submit" class="btn btn-primary">提交</button>
</form>
10.4、编辑用户
- 点击编辑,跳转到编辑页面(将编辑的id携带过去)
- 编辑页面(默认数据,根据id获取并设置到页面中)
- 提交:
- 错误提示
- 数据校验
- 再数据库更新
def user_edit(request, nid):
"""编辑用户"""
# 根据id获取要编辑的哪一行数据
row_object = models.Userinfo.objects.get(id=nid)
if request.method == 'GET':
form = UserModelForm(instance=row_object)
return render(request, 'user_edit.html', {'form': form})
# 保存数据
form = UserModelForm(data=request.POST, instance=row_object)
if form.is_valid():
form.save()
return redirect('/user/list/')
# 错误信息提示
return render(request, 'user_edit.html', {'form': form})
html和添加一样
11、总结-1
ModelForm 针对数据库中的某个表
Form
12、 靓号管理
搜索
# 字典
data_dict = {'id': 12}
row_data = models.Mobile.objects.filter(**data_dict)
# 数字
models.Mobile.objects.filter(id=12) # 等于12
models.Mobile.objects.filter(id__gt=12) # 大于12
models.Mobile.objects.filter(id__gte=12) # 大于等于12
models.Mobile.objects.filter(id__lt=12) # 小于12
models.Mobile.objects.filter(id__lte=12) # 小于等于12
data_dict = {'id__lte': 12}
row_data = models.Mobile.objects.filter(**data_dict)
# 字符串
models.Mobile.objects.filter(mobile__startwith='12') # 以 12 开头
models.Mobile.objects.filter(mobile__endwith='12') # 以 12 结尾
models.Mobile.objects.filter(mobile__contains='12') # 包含 12
models.Mobile.objects.filter(mobile='12') # 等于 12
分页
# 分页查询:根据用户想要访问的页码,计算出起始位置
page = int(request.GET.get('page', 1))
page_size = 8 # 每页想显示多少条数据
start = (page - 1) * page_size
end = page * page_size
# 总数据
data_count = models.Mobile.objects.filter(**data_dict).count() # 获得一共有多少条数据
total_page_count, div = divmod(data_count, page_size) # 求总页码数
if div:
total_page_count += 1 # 总页码
# 计算出,显示当前页的前几个,后几个
plus = 2
if total_page_count <= 2 * plus + 1:
# 数据库中的数据比较少
start_page = 1
end_page = total_page_count
else:
# 数据库中的数据比较多 > 5页
if page <= plus: # 当前页 < 2 时(极小值)
start_page = 1
end_page = 2 * plus + 1
else: # 当前页大于 2
if (page + plus) > total_page_count: # 判断最后的极大值
start_page = total_page_count - 2 * plus
end_page = total_page_count
else: # 中间情况
start_page = page - plus
end_page = page + plus
# 页码
page_str_list = [] # 储存html页码数 "<li><a href="?page=1">1</a></li>"
# 上一页
if page > 1:
prev = '<li><a href="?page={}" ' \
'aria-label="Previous"><span aria-hidden="true">«</span></a></li>'.format(page-1)
else:
prev = '<li><a href="?page={}" ' \
'aria-label="Previous"><span aria-hidden="true">«</span></a></li>'.format(page)
page_str_list.append(prev)
for i in range(start_page, end_page+1):
if i == page:
ele = '<li class="active"><a href="?page={}">{}</a></li>'.format(i, i)
else:
ele = '<li><a href="?page={}">{}</a></li>'.format(i, i)
page_str_list.append(ele)
"""
<li><a href="?page=1">1</a></li>
<li><a href="?page=2">2</a></li>
<li><a href="?page=3">3</a></li>
<li><a href="?page=4">4</a></li>
<li><a href="?page=5">5</a></li>
"""
# 下一页
if page < total_page_count:
next_page = '<li><a href="?page={}" aria-label="Next">' \
'<span aria-hidden="true">»</span></a></li>'.format(page+1)
else:
next_page = '<li><a href="?page={}" aria-label="Next">' \
'<span aria-hidden="true">»</span></a></li>'.format(total_page_count)
page_str_list.append(next_page)
page_string = mark_safe("".join(page_str_list)) # 转义为html
# data_dict为空时,全部查询 # 以level 排序,data_list存储获取的值
data_list = models.Mobile.objects.filter(**data_dict).order_by('level')[start:end]
13、管理员操作
admin.py
from django.shortcuts import render, redirect
from Employee import models
from Employee.utils.form import AdminModel, AdminEditModel
from Employee.utils.pagination import Pagination
def admin_list(request):
"""管理员列表"""
# 搜索
data_dict = {}
search_data = request.GET.get('q', "")
if search_data:
data_dict["username__contains"] = search_data
data_list = models.Admin.objects.filter(**data_dict)
queryset_object = Pagination(request, data_list)
dic_context = {
"data_list": queryset_object.page_queryset, # 数据
"page_string": queryset_object.html(), # 页码
"search_data": search_data, # 搜索得数据
}
if search_data and not queryset_object.page_queryset: # 搜索了,但没有符合的
dic_context.update({'error': '对不起,号码不存在'})
return render(request, 'mobile_list.html', dic_context)
return render(request, 'admin_list.html', dic_context)
def admin_add(request):
"""添加管理员"""
title = '新建管理员'
if request.method == 'GET':
form = AdminModel()
dic_context = {
'form': form,
'title': title,
}
return render(request, 'add.html', dic_context)
form = AdminModel(data=request.POST)
if form.is_valid():
# form.cleaned_data 获得所有输入的值
form.save()
return redirect('/admin/list/')
dic_context = {
'form': form,
'title': title,
}
return render(request, 'add.html', dic_context)
def admin_edit(request, nid):
"""编辑管理员"""
# 对象/None
row_data = models.Admin.objects.filter(id=nid).first()
if not row_data: # 判断数据是否存在
# return render(request, 'error.html', {'error': '数据不存在'})
return redirect('/admin/list/')
title = '修改密码' # 标题名
if request.method == "GET": # get请求显示页面
form = AdminEditModel(instance=row_data, pwd=row_data.password)
username = row_data.username
return render(request, "add.html", {'form': form, 'title': title, 'username': username, 'user_name': '用户名:'})
form = AdminEditModel(instance=row_data, data=request.POST, pwd=row_data.password)
if form.is_valid(): # 判断输入是否合理
form.save()
return redirect('/admin/list/')
return render(request, "add.html", {'form': form, 'title': title})
def admin_delete(request):
nid = request.GET.get('nid')
models.Admin.objects.filter(id=nid).delete()
return redirect('/admin/list/')
form.py
class AdminModel(BootStrapModelForm):
confirm_password = forms.CharField(
label="确认密码",
# widget=forms.PasswordInput(render_value=True), # (render_value=True) 密码不同时,不会置空,默认是False置空
widget=forms.PasswordInput
)
class Meta:
model = models.Admin
fields = ["username", "password", "confirm_password"]
widgets = {
# (render_value=True) 密码不同时,不会置空,默认是False置空
# 'password': forms.PasswordInput(render_value=True)
'password': forms.PasswordInput
}
def clean_password(self):
password = self.cleaned_data.get('password') # 获得输入的password
return md5(password) # 返回md5加密后的值
def clean_confirm_password(self):
password = self.cleaned_data.get('password') # 获得的password是 上面 返回的值
confirm_password = self.cleaned_data.get('confirm_password')
if password != md5(confirm_password):
raise ValidationError('密码不一致,请重新输入!')
return confirm_password # return 什么,保存到数据库的值就是什么
class AdminEditModel(AdminModel):
# class AdminEditModel(BootStrapModelForm):
edit_password = forms.CharField(label='新密码', widget=forms.PasswordInput)
class Meta:
model = models.Admin
fields = ["password", 'edit_password', "confirm_password"] # 添加谁出现谁
widgets = {
'password': forms.PasswordInput
}
def clean_password(self):
password = self.cleaned_data.get('password') # 获得输入的password
if self.pwd != md5(password):
raise ValidationError('密码输入错误')
return md5(password) # 返回md5加密后的值
def clean_edit_password(self):
edit_password = self.cleaned_data.get('edit_password') # 获得输入的password
return md5(edit_password)
def clean_confirm_password(self):
edit_password = self.cleaned_data.get('edit_password') # 获得的password是 上面 返回的值
confirm_password = self.cleaned_data.get('confirm_password')
if edit_password != md5(confirm_password):
raise ValidationError('密码不一致,请重新输入!')
return confirm_password # return 什么,保存到数据库的值就是什么
def __init__(self, pwd, *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}
self.pwd = pwd
14、用户登录
什么是cookie和session?
http、https
session存储在数据库或Redis或文件
14.1、session登录
在其他需要登录才能访问的页面中,都需要加入:
def index(request):
# 检查用户是否已经登录,已登录继续往下走,没有跳转到登录界面
# 获取请求用户的随机字符串,看看session中有没有
# request.session['info']
info = request.session.get('info')
if not info:
return redirect('/login/')
......
目标:在所有视图前面加上 上面判断
14.2、Django的中间件
中间件存方在 django_session 数据库中
- 定义中间件
from django.utils.deprecation import MiddlewareMixin
class M1(MiddlewareMixin):
"""中间件1"""
def process_request(self, request):
# 如果方法中没有返回值(None),意味着可以继续往下走
# 如果有返回值 HttpResponse render redirect
print('m1, 进来了')
def process_response(self, request, response):
print('m1.走了')
return response
class M2(MiddlewareMixin):
"""中间件2"""
def process_request(self, request):
print('m2, 进来了')
def process_response(self, request, response):
print('m2.走了')
return response
- 注册中间件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I6nggq39-1654077355213)(https://gitee.com/cool-dada/blog_img/raw/master/tree/master/img_markdown/202206011747008.png)]
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',
'Employee.middleware.auth.M1',
'Employee.middleware.auth.M2',
]
- 在中间件中的process_request()方法
# 如果方法中没有返回值(None),意味着可以继续往下走
# 如果有返回值 HttpResponse render redirect
14.3、编写登录中间件
from django.shortcuts import redirect
from django.utils.deprecation import MiddlewareMixin
class AuthMiddlewareMixin(MiddlewareMixin):
"""登录"""
def process_request(self, request):
# 排除不需要登录,就能访问的页面
# request.path_info 获取用户请求的url /login/
if request.path_info == '/login/':
return
# 1,读取当前访问的用户的session信息,如果能读到,说明已经登录过,就可以继续向后走
info_dict = request.session.get('info')
if info_dict: # 正确继续往后走
return # 返回空就是可以继续往后走
# 2,如果没有登录,回到登录页面
return redirect('/login/')
14.4、注销
def logout(request):
"""注销"""
request.session.clear() # 清除当前的session
return redirect('/login/')
14.5、模板登录信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-imF7gHiL-1654077355213)(https://gitee.com/cool-dada/blog_img/raw/master/tree/master/img_markdown/202206011747603.png)]
14.5、图片验证码
5.1、生成图片
pip install pillow
5.2、函数
from PIL import Image, ImageDraw, ImageFont, ImageFilter
import random
def check_code(width=100, height=32, char_length=5, font_file=r'Employee/static/plugins/font-text/Monaco.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(30):
draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
# 写干扰圆圈
for i in range(30):
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(3):
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, strs = check_code()
# with open('code.png', 'wb') as f:
# img.save(f, format='png')
# print(strs)
# # 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()
5.3、urls路径
path('image/code/', account.image_code),
5.4、视图
BytesIO介绍:
def image_code(request):
"""生成图片验证码"""
# 调用pillow函数,生成图片
img, code_str = check_code()
# 写入到自己的session中(以便后获取验证码再进行校验)
request.session['code_str'] = code_str
# 给session设置60秒超时,后续成功登录后需要重新设置
request.session.set_expiry(60)
# 导入io模块将图片传给前段
from io import BytesIO
stream = BytesIO()
img.save(stream, 'png')
return HttpResponse(stream.getvalue())
5.5、前端
{# 验证码 #}
<div class="checkImg">
<label>图片验证码</label><br>
{{ form.code }}
<img style="width: 100px;height: 32px;border-radius: 6px;" src="/image/code/" alt="">
<span style="width: 130px;height: 32px;position: absolute;margin-left: -240px;margin-top: 30px">
{{ form.code.errors.0 }}
</span>
</div>
14.6、完整的登录
6.1 urls
# 登录
path('login/', account.login),
path('logout/', account.logout),
# 图片验证码
path('image/code/', account.image_code),
6.2 视图
from django.shortcuts import render, redirect, HttpResponse
from django import forms
from Employee import models
from Employee.utils.createImg import check_code
from Employee.utils.encrypt import md5
class LoginForm(forms.Form):
username = forms.CharField(label='用户名',
widget=forms.TextInput,
required=True, # 不为空, 默认的
)
password = forms.CharField(label='密码', widget=forms.PasswordInput, required=True)
code = forms.CharField(label='验证码', widget=forms.TextInput, required=True)
def clean_password(self):
password = self.cleaned_data.get('password')
return md5(password) # 返回加密后的值
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():
# 验证成功,获取到的用户名和密码
# print(form.cleaned_data) 返回的是字典
# 验证码校验
user_input_code = form.cleaned_data.pop('code') # 获取用户输入的code,并且删去;以防占用内存
auth_image_code = request.session.get('code_str', '') # 获取真正的图片验证码
if auth_image_code.upper() != user_input_code.upper(): # 验证码不正确,返回错误数据
form.add_error('code', '验证码错误')
return render(request, 'login.html', {'form': form})
# 去数据库校验
# models.Admin.objects.filter(username=xxx, password=xxx).first()
admin_object = models.Admin.objects.filter(**form.cleaned_data).first() # 传入一个字典
if not admin_object:
form.add_error('password', '用户名或密码错误')
return render(request, 'login.html', {'form': form})
# 登录成功
# session 存储用户名
request.session['info'] = {'id': admin_object.id, 'username': admin_object.username}
request.session.set_expiry(60 * 60 * 24 * 7) # 重新设置登录超时7天;因为在获取验证码时设置了过期时间,所有需要重新设置
return redirect('/admin/list/')
return render(request, 'login.html', {'form': form})
def logout(request):
"""注销"""
request.session.clear() # 清除当前的session
return redirect('/login/')
def image_code(request):
"""生成图片验证码"""
# 调用pillow函数,生成图片
img, code_str = check_code()
# 写入到自己的session中(以便后获取验证码再进行校验)
request.session['code_str'] = code_str
# 给session设置60秒超时,后续成功登录后需要重新设置
request.session.set_expiry(60)
# 导入io模块将图片传给前段
from io import BytesIO
stream = BytesIO()
img.save(stream, 'png')
return HttpResponse(stream.getvalue())
6.3、页面
{% load static%}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1-dist/css/bootstrap.css' %}">
<style>
* {
margin: 0;
padding: 0;
}
body {
display: flex;
align-items: center;
justify-content: center;
background: url('../static/img/A-黑.jpg') no-repeat 0px 0px;
height: 100%;
}
#loginDiv {
width: 400px;
display: flex;
justify-content: center;
align-items: center;
height: 400px;
margin-top: 100px;
background-color: rgba(75, 81, 95, 0.3);
box-shadow: 7px 7px 17px rgba(52, 56, 66, 0.5);
border-radius: 250px;
}
label {
margin-top: 30px;
margin-left: 20px;
color: azure;
}
span{
color: red;
margin-top: 55px;
margin-left: -140px;
position: absolute
}
input {
margin-left: 15px;
border-radius: 5px;
border-style: hidden;
height: 30px;
width: 140px;
background-color: rgba(216, 191, 216, 0.5);
outline: none;
color: #f0edf3;
padding-left: 10px;
}
.checkImg{
position: absolute;
margin-top: -5px;
}
.checkInput::placeholder {
color: rgba(255, 255, 255, 0.93);
opacity: 0.6;
}
.button {
border-color: cornsilk;
background-color: rgba(100, 149, 237, .7);
color: aliceblue;
border-style: hidden;
border-radius: 5px;
width: 100px;
height: 31px;
font-size: 16px;
margin-top: 20px;
}
</style>
<style type="text/css">
input::-ms-input-placeholder{text-align: center;}
input::-webkit-input-placeholder{text-align: center;}
</style>
</head>
<body>
<div id="loginDiv">
<form action="" id="form" method="post" novalidate>
{% csrf_token %}
<h1 style="text-align: center;color: aliceblue;">用户登录</h1>
<label>用户名: </label>
{{ form.username }}
<span>{{ form.username.errors.0 }}</span>
<br>
<label>密 码:</label>
{{ form.password }}
<span>{{ form.password.errors.0 }}</span>
{# 验证码 #}
<div class="checkImg">
<label>图片验证码</label><br>
{{ form.code }}
<img style="width: 100px;height: 32px;border-radius: 6px;" src="/image/code/" alt="">
<span style="width: 130px;height: 32px;position: absolute;margin-left: -240px;margin-top: 30px">
{{ form.code.errors.0 }}
</span>
</div>
<br><br><br><br>
<div style="text-align: center;margin-top: 30px;">
<input type="submit" class="button" value="登录">
</div>
</form>
</div>
</body>
</html>
15、Ajax
浏览器向网站发送请求时:URL和表单的形式提交
- GET
- POST
特点:页面刷新
除此之外,基础Ajax向后台请求
- 依赖jQuery
- 编写jQuery代码
$.ajax({
url:"发送得地址",
type:"get",
data:{
n1:123,
n2:456
},
success:function(res){
console.log(res);
}
})
15.1、get请求
{% extends 'layout.html' %}
{% block content %}
<h1>任务管理</h1>
<h3>实例1</h3>
<input type="button" class="btn btn-primary" value="点击" onclick="clickMe()" >
{% endblock %}
{% block js %}
<script type="text/javascript">
function clickMe() {
$.ajax({
url: '/task/ajax/',
type: 'get',
data: {
n1: 123,
n2: 456
},
{# 成功之后,res是返回的值 #}
success: function (res) {
console.log(res)
}
})
}
</script>
{% endblock %}
from django.http import HttpResponse
from django.shortcuts import render
def task_list(request):
"""任务列表"""
return render(request, 'task_list.html')
def task_ajax(request):
print(request.GET)
return HttpResponse('成功')
# 任务管理
path('task/list/', task.task_list),
path('task/ajax/', task.task_ajax),
15.2、post请求
from django.http import HttpResponse
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
def task_list(request):
"""任务列表"""
return render(request, 'task_list.html')
@csrf_exempt # 免除post请求,就在可以获取Ajax post发送的内容
def task_ajax(request):
print(request.GET)
print(request.POST)
return HttpResponse('成功')
15.3、关闭绑定事件
{% extends 'layout.html' %}
{% block content %}
<h1>任务管理</h1>
<h3>实例1</h3>
<input type="button" class="btn btn-primary" value="点击" id="btn1" >
{% endblock %}
{% block js %}
<script type="text/javascript">
$(function () {
//页面加载完成之后代码自动执行,函数里的内容
//定义一个函数,
bindBtn1Event();
})
function bindBtn1Event() {//函数里嵌套一个函数
$("#btn1").click(function () {
$.ajax({
url: '/task/ajax/',
type: 'post',
data: {
n1: 123,
n2: 456
},
{# 成功之后,res是返回的值 #}
success: function (res) {
console.log(res)
}
})
})
}
</script>
{% endblock %}
15.4、Ajax请求的返回值
一般都会返回json格式
前端:
{% extends 'layout.html' %}
{% block content %}
<h1>任务管理</h1>
<h3>实例1</h3>
<input type="button" id="btn1" class="btn btn-primary" value="点击">
<h3>实例2</h3>
<input type="text" id="txtUser" placeholder="姓名">
<input type="text" id="txtAge" placeholder="年龄">
<input type="button" id="btn2" class="btn btn-primary" value="点击">
<h3>实例3</h3>
<form action="" id="form3">
<input type="text" name="user" placeholder="姓名">
<input type="text" name="age" placeholder="年龄">
<input type="text" name="address" placeholder="地址">
<input type="text" name="email" placeholder="邮箱">
<input type="button" id="btn2" class="btn btn-primary" value="点击">
</form>
{% endblock %}
{% block js %}
<script type="text/javascript">
$(function () {
//页面加载完成之后代码自动执行,函数里的内容
bindBtn1Event();
bindBtn2Event();//返回获取的内容(用户输入)
bindBtn3Event();//返回多个内容(表单)
})
function bindBtn1Event() {//函数里嵌套一个函数
$("#btn1").click(function () {
$.ajax({
url: '/task/ajax/',
type: 'post',
data: {
n1: 123,
n2: 456
},
dataType: 'JSON', //处理请求返回的数据的类型
{# 成功之后,res是返回的值 #}
success: function (res) {
console.log(res);
console.log(res.status);
console.log(res.name);
}
})
})
}
function bindBtn2Event() {//函数里嵌套一个函数
$("#btn2").click(function () {
$.ajax({
url: '/task/ajax/',
type: 'post',
data: {
name: $('#txtUser').val(), //获取id=txtUser的内容
age: $('#txtAge').val()
},
dataType: 'JSON', //处理请求返回的数据的类型
{# 成功之后,res是返回的值 #}
success: function (res) {
console.log(res);
console.log(res.status);
console.log(res.name);
}
})
})
}
function bindBtn3Event() {//函数里嵌套一个函数
$("#form3").click(function () {
$.ajax({
url: '/task/ajax/',
type: 'post',
data: $('#form3').serialize(), //自动获取表单中所有输入框中的内容
dataType: 'JSON', //处理请求返回的数据的类型
{# 成功之后,res是返回的值 #}
success: function (res) {
console.log(res);
console.log(res.status);
console.log(res.name);
}
})
})
}
</script>
{% endblock %}
后端:
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
def task_list(request):
"""任务列表"""
return render(request, 'task_list.html')
@csrf_exempt # 免除post请求,就在可以获取Ajax post发送的内容
def task_ajax(request):
print(request.GET)
print(request.POST)
data_dict = {'status': True, 'name': '李锦彪'}
return JsonResponse(data_dict)
16、订单
html
{% extends 'layout.html' %}
{% block content %}
<div>
<input type="button" value="新建订单1" class="btn btn-primary" data-toggle="modal" data-target="#myModal">
<input id="btnAdd" type="button" value="新建订单2" class="btn btn-primary">
</div>
<!-- 新建/编辑订单对话框 -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel"></h4>
</div>
<div class="modal-body">
<div class="panel-body">
<form id="formAdd">
<div class="clearfix">
{% for field in form %}
<div class="form-group col-xs-6" style="position: relative;margin-bottom: 20px">
<label>{{ field.label }}</label>
{{ field }}
<span class="error-msg"
style="color: red;position: absolute">{{ field.errors.0 }}</span>
</div>
{% endfor %}
</div>
</form>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button id="btnSave" type="button" class="btn btn-primary">保存</button>
</div>
</div>
</div>
</div>
<br>
{# 删除对话框 #}
<!-- Modal -->
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="alert alert-danger alert-dismissible fade in" role="alert">
<h4>是否确定删除?</h4>
<p>删除后,所有关联的数据都会被删除!!!</p>
<p style="text-align: right">
<button type="button" class="btn btn-danger" id="confirm-delete">确定</button>
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
</p>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list"></span>
订单列表
</div>
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>订单号</th>
<th>商品名</th>
<th>价格</th>
<th>状态</th>
<th>用户</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for obj in queryset %}
<tr uid="{{ obj.id }}">
<td>{{ obj.id }}</td>
<td>{{ obj.oid }}</td>
<td>{{ obj.title }}</td>
<td>{{ obj.price }}</td>
<td>{{ obj.get_status_display }}</td>
<td>{{ obj.admin }}</td>
<td>
{# 编辑#}
<button eid="{{ obj.id }}" class="btn btn-primary btn-xs btn-edit">
<span class="glyphicon glyphicon-cog"></span>
</button>
{# 删除 #}
<button uid="{{ obj.id }}" class="btn btn-danger btn-xs btn-delete">
<span class="glyphicon glyphicon-trash"></span>
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<ul class="pagination" style="text-align: center">
{{ page_string }}
</ul>
{% endblock %}
{% block js %}
<script type="text/javascript">
var DELETE_ID;
var EDIT_ID;
$(function () {
bindBtnAdd();
bindBtnSave();
bindBtnDelete();
bindConfirmDelete();
bindBtnEdit();
})
function bindBtnAdd() {
$('#btnAdd').click(function () {
//将正在编辑的id置空
EDIT_ID = undefined;
{# 置空 #}
$('#formAdd')[0].reset();
{# 修改对话框标题 #}
$('.modal-title').text('新建订单')
$('#myModal').modal('show');
});
}
function bindBtnSave() {
$('#btnSave').click(function () {
//清除错误信息
$('.error-msg').empty();
//判断
if (EDIT_ID) {
//编辑
$.ajax({
url: '/order/edit/' + '?eid=' + EDIT_ID,
type: 'post',
data: $('#formAdd').serialize(),
dataType: 'JSON',
success: function (res) {
if (res.status) {
//清空表单 $('#formAdd')是jQuery对象 -> $('#formAdd')[0] DOM对象
$('#formAdd')[0].reset();
//关闭对话框
$('#myModal').modal('hide');
location.reload(); //刷新页面
} else {
if (res.tips) {
alert(res.tips)
} else {
//把错误信息显示在对话框
$.each(res.error, function (name, data) {
$("#id_" + name).next().text(data[0]);
});
}
}
}
});
} else {
//添加 向后台发送信息
$.ajax({
url: '/order/add/',
type: 'post',
data: $('#formAdd').serialize(),
dataType: 'JSON',
success: function (res) {
if (res.status) {
//alert('添加成功');
//清空表单 $('#formAdd')是jQuery对象 -> $('#formAdd')[0] DOM对象
$('#formAdd')[0].reset();
//关闭对话框
$('#myModal').modal('hide');
location.reload(); //刷新页面
} else {
$.each(res.error, function (name, data) {
$("#id_" + name).next().text(data[0]);
});
}
}
});
}
});
}
function bindBtnDelete() {
$('.btn-delete').click(function () {
//获取当前行的ID并赋值给全局变量 deleteModal
$('#deleteModal').modal('show');
DELETE_ID = $(this).attr('uid');
});
}
function bindConfirmDelete() {
//点击确认按钮,将全局变量传给后台
$('#confirm-delete').click(function () {
$.ajax({
url: '/order/delete/',
type: 'GET',
data: {
uid: DELETE_ID
},
dataType: 'JSON',
success: function (res) {
if (res.status) {
//删除成功
{#//隐藏对话框#}
{#$('.deleteModal').modal('hide');#}
{#//在页面当前行数据删除(js)#}
{#$("tr[uid='" + DELETE_ID + "']").remove();#}
{#//要删除的对话框置为0#}
{#DELETE_ID = 0;#}
location.reload();
} else {
//删除失败
alert(res.error)
}
}
});
});
}
function bindBtnEdit() {
$('.btn-edit').click(function () {
{# 拿到要编辑的id #}
EDIT_ID = $(this).attr('eid')
{# 发送Ajax 去后端获取当前行的相关内容 #}
$.ajax({
url: '/order/edit/',
type: 'get',
data: {
eid: EDIT_ID,
},
dataType: 'JSON',
success: function (res) {
{# 置空 #}
$('#formAdd')[0].reset();
if (res) {
//将数据默认赋值到对话框
$.each(res.data, function (key, value) {
$('#id_' + key).val(value);
});
{# 修改对话框标题 #}
$('.modal-title').text('编辑订单')
{# 显示对话框 #}
$('#myModal').modal('show');
} else {
alert(res.error);
}
}
});
});
}
</script>
{% endblock %}
视图
import random
from datetime import datetime
from django.http import JsonResponse
from django.shortcuts import render, redirect
from django.views.decorators.csrf import csrf_exempt
from Employee import models
from Employee.utils.form import OrderModelForm
# 订单号生成
from Employee.utils.pagination import Pagination
random_oid = datetime.now().strftime('%Y%m%d%H%M%S') + str(random.randint(1000, 9999))
def order_list(request):
form = OrderModelForm()
# 1、根据自己的情况去筛选自己的数据
queryset = models.Order.objects.all() # 获得所有数据
# 2,、实例化分页对象
page_object = Pagination(request, queryset)
dic_context = {
'queryset': page_object.page_queryset, # 分完页的数据
'page_string': page_object.html(), # 生成页码
'form': form,
}
return render(request, 'order_list.html', dic_context)
@csrf_exempt
def order_add(request):
"""新建订单(Ajax)"""
form = OrderModelForm(request.POST)
if form.is_valid():
# 创建自定义订单号
form.instance.oid = random_oid
# 创建管理员(登录的是谁就是谁)
form.instance.admin_id = request.session['info']['id']
# 保存到数据库中
form.save()
context = {
'status': True
}
return JsonResponse(context)
# 返回错误信息
return JsonResponse({'status': False, 'error': form.errors})
def order_delete(request):
"""删除订单"""
uid = request.GET.get('uid')
if models.Order.objects.filter(id=uid).exists(): # 判断是否存在
models.Order.objects.filter(id=uid).delete()
return JsonResponse({'status': True})
return JsonResponse({'status': False, 'error': '删除错误,数据不存在'})
@csrf_exempt
def order_edit(request):
if request.method == 'GET':
"""根据id获取订单信息 get 请求"""
eid = request.GET.get('eid')
# row_object = models.Order.objects.filter(id=eid).filter() # 对象
if models.Order.objects.filter(id=eid).filter():
# 获取到的是字典
row_dict = models.Order.objects.filter(id=eid).values('title', 'price', 'status').first()
return JsonResponse({'status': True, 'data': row_dict})
return JsonResponse({'status': False, 'error': '数据不存在'})
"""编辑订单 POST请求"""
eid = request.GET.get('eid')
row_object = models.Order.objects.filter(id=eid).first()
if not models.Order.objects.filter(id=eid).filter():
return JsonResponse({'status': False, 'tips': '数据不存在,请刷新重试'})
form = OrderModelForm(data=request.POST, instance=row_object)
if form.is_valid():
form.save()
return JsonResponse({'status': True})
# 返回错误信息
return JsonResponse({'status': False, 'error': form.errors})
17、文件上传
17.1、基本操作
{# enctype="multipart/form-data" 支持上传文件 #}
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="text" name="username">
<input type="file" name="avater">
<input type="submit">
</form>
from django.shortcuts import render, HttpResponse
def upload_list(request):
if request.method == 'GET':
return render(request, 'upload_list.html')
# # 'username': ['15751083927']
# print(request.POST) # 请求体中的数据
# # {'avater': [<InMemoryUploadedFile: 1.png (image/png)>]}
# print(request.FILES) # 发过来的文件 {}
file_object = request.FILES.get('avater')
print(file_object.name) # 文件名
f = open('a1.png', 'wb')
for chunk in file_object.chunks():
f.write(chunk) # 读一点写入一点
f.close()
return HttpResponse('...')
17.2、Excel批量上传
def depart_multi(request):
"""批量添加"""
from django.core.files.uploadedfile import InMemoryUploadedFile
from openpyxl import load_workbook
# 获取用户上传的文件对象
file_object = request.FILES.get('exc')
# 对象传递给openpyxl
wb = load_workbook(file_object) # 或者是文件路径
sheet = wb.worksheets[0]
# 循环获取每一行数据
for row in sheet.iter_rows(min_row=2):
text = row[0].value
# 添加到数据库
if not models.Department.objects.filter(title=text).exists():
models.Department.objects.create(title=text)
return redirect('/depart/list/')
<form method="post" enctype="multipart/form-data" action="/depart/multi/">
{% csrf_token %}
<input type="file" name="exc">
<br>
<input type="submit" value="上传" class="btn-info btn btn-sm">
</form>
17.3、混合数据(form)
提交页面时:用户输入的数据+文件(输入不能为空、报错)。
- form生成的html标签:type=file
- 表单的验证
- form.clean_data 获取数据 + 文件对象
{% extends 'layout.html' %}
{% block content %}
<h1>{{ title }}</h1>
<form method="post" enctype="multipart/form-data" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label>{{ field.label }}</label>
{{ field }}
<span style="color: red">{{ field.errors.0 }}</span>
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">保存</button>
</form>
{% endblock %}
后端:
class UpForm(forms.Form):
name = forms.CharField(label='姓名')
age = forms.IntegerField(label='年龄')
img = forms.FileField(label='头像')
def upload_form(request):
"""获取混合数据"""
title = 'Form上传'
if request.method == "GET":
form = UpForm()
return render(request, 'upload_form.html', {'form': form, 'title': title})
form = UpForm(data=request.POST, files=request.FILES)
if form.is_valid():
# {'name': '李锦彪', 'age': 23, 'img': <InMemoryUploadedFile: 35.jpg (image/jpeg)>}
# print(form.cleaned_data)
# 获取到的内容要自己处理
# 1.读取图片内容,写入到文件夹中并获取文件的路径
img_object = form.cleaned_data.get('img')
# file_path = 'Employee/static/img/{}'.format(img_object.name) /格式不同,所以使用os
db_file_path = os.path.join('static', 'img', img_object.name) # 数据库存取地址 方便网页拼接url获取
file_path = os.path.join('Employee', db_file_path)
f = open(file_path, 'wb')
for chunk in img_object.chunks():
f.write(chunk)
f.close()
# 2.将图片文件路径写入到数据库
models.Boss.objects.create(
name=form.cleaned_data['name'],
age=form.cleaned_data['age'],
img=db_file_path
)
return redirect('/upload/form/')
return render(request, 'upload_form.html', {'form': form, 'title': title})
注意:就目前而言,所有的静态文件都只能放在static目录
在Django的开发过程中两个特殊的文件夹
- static。存放静态文件
- media:用户上传的数据目录
17.4、启用media,存数据
存储用户传来的数据
在urls.py中进行配置:
from django.conf import settings
from django.urls import path, re_path
from django.views.static import serve # 加载静态文件
urlpatterns = [
re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}, name='media')
]
在settings.py中进行配置:
import os
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
media目录所在位置:
在浏览器中直接访问:
后端存储
def upload_form(request):
"""获取混合数据"""
title = 'Form上传'
if request.method == "GET":
form = UpForm()
return render(request, 'upload_form.html', {'form': form, 'title': title})
form = UpForm(data=request.POST, files=request.FILES)
if form.is_valid():
# {'name': '李锦彪', 'age': 23, 'img': <InMemoryUploadedFile: 35.jpg (image/jpeg)>}
# print(form.cleaned_data)
# 获取到的内容要自己处理
# 1.读取图片内容,写入到文件夹中并获取文件的路径
img_object = form.cleaned_data.get('img')
media_path = os.path.join('media', img_object.name) # media/xxxx
f = open(media_path, 'wb')
for chunk in img_object.chunks():
f.write(chunk)
f.close()
# 2.将图片文件路径写入到数据库
models.Boss.objects.create(
name=form.cleaned_data['name'],
age=form.cleaned_data['age'],
img=media_path
)
return redirect('/upload/form/')
return render(request, 'upload_form.html', {'form': form, 'title': title})
17.5、混合数据(ModelForm)
models.py
class City(models.Model):
""""城市"""
title = models.CharField(verbose_name='城市', max_length=32)
count = models.IntegerField(verbose_name='人口')
# 本质上数据库也是CharField, 但是自动保存数据 路径 :media/city/xxx
img = models.FileField(verbose_name='logo', max_length=128, upload_to='city/')
定义ModelForm:
class CityModelForm(forms.ModelForm):
class Meta:
model = models.City
fields = '__all__'
视图
def upload_modelform(request):
"""获取混合数据modelform"""
title = 'ModelForm'
if request.method == 'GET':
form = CityModelForm()
queryset = models.City.objects.all()
return render(request, 'upload_modelform.html', {'form': form, 'title': title, 'queryset': queryset})
form = CityModelForm(data=request.POST, files=request.FILES)
if form.is_valid():
# 对于文件:自动保存
# 字段+上传路径写入到数据库
form.save()
return redirect('/upload/modelform/')
return render(request, 'upload_modelform.html', {'form': form, 'title': title})
前段
包括显示内容
{% extends 'layout.html' %}
{% block content %}
<h1>{{ title }}</h1>
<form method="post" enctype="multipart/form-data" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label>{{ field.label }}</label>
{{ field }}
<span style="color: red">{{ field.errors.0 }}</span>
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">保存</button>
</form>
<div class="panel panel-default">
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list"></span>
管理员列表
</div>
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>城市名</th>
<th>人口</th>
<th>logo</th>
</tr>
</thead>
<tbody>
{% for obj in queryset %}
<tr>
<td>{{ obj.id }}</td>
<td>{{ obj.title }}</td>
<td>{{ obj.count }}</td>
<td>
<img src="/media/{{ obj.img }}" style="height: 100px;width: 100px">
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
Django 函数+知识点
Django转义总结:escape、autoescape、safe、mark_safe
https://blog.csdn.net/bbwangj/article/details/79992863
分页 --类
"""
自定义分页组件, 以后想使用这个分页组件,做一下几步
后端:
def mobile_list(request):
1、根据自己的情况去筛选自己的数据
queryset = models.Mobile.objects.all() # 获得所有数据
2,、实例化分页对象
page_object = Pagination(request, queryset)
dic_context = {
'data_list': page_object.page_queryset, # 分完页的数据
'page_string': page_object.html(), # 生成页码
}
return render(request, 'mobile_list.html', dic_context)
前段:
<div class="panel panel-default">
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list"></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>
<td>{{ obj.id }}</td>
<td>{{ obj.mobile }}</td>
<td>{{ obj.price }}</td>
<td>{{ obj.get_level_display }}</td>
<td>{{ obj.get_status_display }}</td>
<td>
{# 编辑#}
<a href="/mobile/{{ obj.id }}/edit/" class="btn btn-primary btn-xs">
<span class="glyphicon glyphicon-cog"></span>
</a>
{# 删除#}
<a href="/mobile/{{ obj.id }}/delete/" class="btn btn-danger btn-xs">
<span class="glyphicon glyphicon-trash"></span>
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<ul class="pagination" style="text-align: center">
{{ page_string }}
</ul>
"""
from django.utils.safestring import mark_safe
import copy
class Pagination(object):
def __init__(self, request, queryset, page_size=8, page_param="page", plus=2):
"""
:param request: 请求的对象
:param queryset: 符合条件的数据
:param page_size: 每页的数量
:param page_param: 在URL中传递的获取分页的参数,例如:/mobile/list/?page=12
:param plus: 导航页码
"""
page = request.GET.get(page_param, "1") # 获取前段传来的page,默认值为1
# 拿到url参数
query_dict = copy.deepcopy(request.GET)
query_dict._mutable = True
self.query_dict = query_dict # 拿到url参数 例如:page=q=1&page=1
if page.isdecimal(): # 判断是否是数字
page = int(page)
else:
page = 1
self.page = page # 获取哪一页
self.page_size = page_size # 页面展示的数据有几条
self.page_param = page_param # 页面
self.start = (page - 1) * page_size # 展示首页
self.end = page * page_size # 展示尾页
self.page_queryset = queryset[self.start:self.end]
data_count = queryset.count() # 获得一共有多少条数据
total_page_count, div = divmod(data_count, self.page_size) # 求总页码数
if div:
total_page_count += 1 # 总页码
self.total_page_count = total_page_count # 总页码
self.plus = plus # 只显示多少页 2*plus+1
def html(self):
# 计算出,显示当前页的前几个,后几个
if self.total_page_count <= 2 * self.plus + 1:
# 数据库中的数据比较少
start_page = 1
end_page = self.total_page_count
else:
# 数据库中的数据比较多 > 5页
if self.page <= self.plus: # 当前页 < 2 时(极小值)
start_page = 1
end_page = 2 * self.plus + 1
else: # 当前页大于 2
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 = [] # 储存html页码数 "<li><a href="?page=1">1</a></li>"
# 首页
self.query_dict.setlist(self.page_param, [1])
head_page = '<li><a href="?{}">首页</a></li>'.format(self.query_dict.urlencode())
page_str_list.append(head_page)
# 上一页
if self.page > 1:
self.query_dict.setlist(self.page_param, [self.page - 1])
prev = '<li><a href="?{}" ' \
'aria-label="Previous"><span aria-hidden="true">«</span></a>' \
'</li>'.format(self.query_dict.urlencode())
else:
self.query_dict.setlist(self.page_param, [self.page])
prev = '<li><a href="?{}" ' \
'aria-label="Previous"><span aria-hidden="true">«</span></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)
"""
<li><a href="?page=1">1</a></li>
<li><a href="?page=2">2</a></li>
<li><a href="?page=3">3</a></li>
"""
# 下一页
if self.page < self.total_page_count:
self.query_dict.setlist(self.page_param, [self.page + 1])
next_page = '<li><a href="?{}" aria-label="Next">' \
'<span aria-hidden="true">»</span></a></li>'.format(self.query_dict.urlencode())
else:
self.query_dict.setlist(self.page_param, [self.total_page_count])
next_page = '<li><a href="?{}" aria-label="Next">' \
'<span aria-hidden="true">»</span></a></li>'.format(self.query_dict.urlencode())
page_str_list.append(next_page)
# 尾页
self.query_dict.setlist(self.page_param, [self.total_page_count])
tail_page = '<li><a href="?{}">尾页</a></li>'.format(self.query_dict.urlencode())
page_str_list.append(tail_page)
page_string = mark_safe("".join(page_str_list)) # 转义为html
return page_string
bootstrap样式-父类
from django import forms
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}
封装
md5加密
from django.conf import settings
import hashlib
def md5(data_string): # md5加密
obj = hashlib.md5(settings.SECRET_KEY.encode('utf-8'))
obj.update(data_string.encode('utf-8'))
return obj.hexdigest()
数据库中获取数据
对象/字典
# 对象当前行的所有数据
row_object = models.Order.objects.filter(id=eid).filter()
# 获取到的是字典
row_dict = models.Order.objects.filter(id=eid).values('title', 'price', 'status').first()
# queryset = {obj,obj ..}
queryset = models.Order.objects.all()
# queryset = { {'xx': 'xx', 'xx': 'xxx'}, {'xx': 'xxx', 'xx': 'xxx'} }
queryset = models.Order.objects.all().values('xx', 'xx')
# queryset = {(1, 'xx'), (2, 'xx')....}
queryset = models.Order.objects.all().values_list('id', 'title')
柱状图
{% extends 'layout.html' %}
{% load static %}
{% block content %}
<h2>数据统计</h2>
<div class="col-sm-8">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">柱状图</h3>
</div>
<div class="panel-body">
<div id="m2" style="height: 400px; width: 100%">
</div>
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script src="{% static 'js/echarts.js' %}"></script>
<script type="text/javascript">
$(function () {
initBar();
});
//初始化柱状图
function initBar() {
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('m2'));
// 指定图表的配置项和数据
var option = {
title: {
text: '业绩'
},
tooltip: {},
legend: {
data: [],//后台获取
bottom: 0,
},
xAxis: { //x轴
data: []//后台获取
},
yAxis: {},//y轴
series: []//后台获取
};
//向后台发送请求,获取数据
$.ajax({
url: '/chart/bar/',
type: 'get',
dataType: 'JSON',
success: function (res) {
//将后台返回的数据,更新到option中
if (res.status) {
// option->legend->data
option.legend.data = res.data.legend;
option.xAxis.data = res.data.x_axis;
option.series = res.data.series_list;
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
}
}
});
}
</script>
{% endblock %}
https://echarts.apache.org/zh/index.html
总结
- 创建Django项目
- 修改__ init __.py
import pymysql
pymysql.install_as_MySQLdb()
- settings.py中的DIR templates删除
- 创建app和注册app
python manage.py startapp xxx
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'Employee.apps.EmployeeConfig', # app注册
]
- 配置静态文件路径 & 模板路径(放在app目录下)
- 配置数据库相关操作
- 第三方模块 mysqlclient
- 自己先去数据库创建一个数据库
- 配置数据库连接settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'ljb', # 数据库名字
'USER': 'root', # 账号
'PASSWORD': '187365', # 密码
'HOST': '127.0.0.1', # 主机
'PORT': 3306, # 端口号
}
}
- 在app下的models.py中编写表
from django.db import models
class Department(models.Model):
"""部门表"""
title = models.CharField(verbose_name='标题', max_length=32)
def __str__(self):
return self.title
- 执行两个命令
python manage.py makemigrations
python manage.py migrate
- 在urls.py,路由(url和函数的对应关系)
- 在views,试图函数,编写业务逻辑
- templates目录下编写html文件
- ModelForm & Form组件,在我们开发增删改查功能
- 生成html标签(生成默认值)
- 请求数据进行校验
- 保存到数据库(ModelForm)
- 获取错误信息
- Cookie和session用户信息保存起来
- 中间件,基于中间件实现用户认证,基于:process_request
- ORM操作
models.User.objects.filter(id="")
- 分页组件。
{% endblock %}
https://echarts.apache.org/zh/index.html
## 总结
- 创建Django项目
- 修改__ init __.py
```python
import pymysql
pymysql.install_as_MySQLdb()
- settings.py中的DIR templates删除
- 创建app和注册app
python manage.py startapp xxx
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'Employee.apps.EmployeeConfig', # app注册
]
- 配置静态文件路径 & 模板路径(放在app目录下)
- 配置数据库相关操作
- 第三方模块 mysqlclient
- 自己先去数据库创建一个数据库
- 配置数据库连接settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'ljb', # 数据库名字
'USER': 'root', # 账号
'PASSWORD': '187365', # 密码
'HOST': '127.0.0.1', # 主机
'PORT': 3306, # 端口号
}
}
- 在app下的models.py中编写表
from django.db import models
class Department(models.Model):
"""部门表"""
title = models.CharField(verbose_name='标题', max_length=32)
def __str__(self):
return self.title
- 执行两个命令
python manage.py makemigrations
python manage.py migrate
- 在urls.py,路由(url和函数的对应关系)
- 在views,试图函数,编写业务逻辑
- templates目录下编写html文件
- ModelForm & Form组件,在我们开发增删改查功能
- 生成html标签(生成默认值)
- 请求数据进行校验
- 保存到数据库(ModelForm)
- 获取错误信息
- Cookie和session用户信息保存起来
- 中间件,基于中间件实现用户认证,基于:process_request
- ORM操作
models.User.objects.filter(id="")
- 分页组件。