文章目录

  • 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 导出为OVF 无法选择_pycharm
  • 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】
    。。。

创建:

导出为OVF 无法选择_pycharm_02

app01
	__init__.py
    admin.py		【固定,不用动】Django默认提供了admin后台管理
    apps.py			【固定,不用动】app启动类
    migrations		【固定,不用动】数据库变更记录
    	__init__.py
    models.py		【**重要**】对数据库操作
    tests.py		【固定,不用动】单元测试
    views.py		【**重要**】,函数

4、启动运行Django

4.1确保app已注册

导出为OVF 无法选择_django_03

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项目

导出为OVF 无法选择_pycharm_04

4.5、templates模板

导出为OVF 无法选择_html_05

4.6、静态文件

在开发过程中一般将 图片、css、js都会当做静态文件处理

static文件夹下存放静态文件

  • plugins:用于存放插件

导出为OVF 无法选择_pycharm_06

插件使用+引入

{% 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内部:

  1. 读取含有模板语法的html文件
  2. 内部进行渲染(模板语法执行并替换数据),最终得到只包含html标签的字符串
  3. 将渲染(替换)完成的字符串返还给用户浏览器

案例:伪联通新闻中心

**第一步:**urls.py中创建路径

导出为OVF 无法选择_python_07

第二步: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 %}

导出为OVF 无法选择_django_08

导出为OVF 无法选择_python_09

第一步: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文件夹,删除

导出为OVF 无法选择_导出为OVF 无法选择_10

8.2、创建app,终端运行 python manage.py startapp xxx
8.3、注册app

导出为OVF 无法选择_python_11

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

注意:

报错:

导出为OVF 无法选择_django_12

解决:

导出为OVF 无法选择_html_13

原因:PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中则使用mysqldb。
MySQLdb并不支持Python3.

8.7、创建静态文件和模板文件

导出为OVF 无法选择_html_14

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 数据库中

  • 定义中间件

导出为OVF 无法选择_django_15

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目录所在位置:

导出为OVF 无法选择_python_16

在浏览器中直接访问:

导出为OVF 无法选择_html_17

后端存储

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}

封装

导出为OVF 无法选择_python_18

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="")
  • 分页组件。