Django(一)

推荐教程:https://code.ziqiangxuetang.com/django/django-tutorial.html

MVC设计模式(Model,View,Controller)

image

  1 Model:用于封装与应用程序的业务逻辑相关的数据及对数据的处理方法,是Web应用程序中用于处理应用程序的数据逻辑部分,Model通常只提供功能性的接口,通过这些接口可以获取Model的所有功能。
  2 
  3 View:负责数据的显示和呈现,View是对用户的直接输出。
  4 
  5 Controller:负责从用户端收集用户的输入,可以看成提供View的反向功能,主要处理用户交互。
  6 
MVC说明

Django是MVT模式,本质上还是MVC模式

  1 MVT本质上与MVC没什么差别,也是各组件之间为了保持松耦合关系,只是定义上有些许不同。
  2 
  3 Model:负责业务对象与数据库(ORM)的对象
  4 
  5 View:负责业务逻辑,并在适当的时候调用Model和Template
  6 
  7 Template:负责把页面展示给用户
  8 
  9 注意:Django中还有一个url分发器(也可以叫做路由),主要用来将一个个URL页面的请求分发给不同的View进行处理,View再调用相应的Model和Template。
 10 
Mvt说明

image

1.虚拟环境的安装

    作用:隔离项目运行环境

    安装virtualenvwrapper,详情见环境搭建之virtualenv的安装

2.配置Django项目开发环境

    创建项目虚拟环境: (删除:rmvirtualenv 虚拟环境名称)

       mkvirtualenv --python=/usr/local/python3.5.3/bin/python venv_name

       其中,--python=的是你要使用的python解释器的路径,后面的是虚拟环境的名字

    进入虚拟环境: (退出:deactivate)

        workon 虚拟环境名称

        指定python解释器—>用绝对路径,在编译器中编辑时要指定编辑器的解释器。

    安装XXX依赖包:pip install XXX

        pip freeze: 查看虚拟环境新安装的包

        pip install django==2.2 (== 用来指定需要安装的版本)

3.Django项目

    创建项目:django-admin startproject axf

    Django 目录介绍

  1 manage.py:
  2  是Django用于管理本项目的命令行工具,之后进行站点运行,数据库自动生成等都是通过本文件完成。
  3 
  4 axf/__init__.py:
  5  告诉python该目录是一个python包,暂无内容,后期一些工具的初始化可能会用到
  6 
  7 axf/settings.py:
  8  Django项目的配置文件,默认状态其中定义了本项目引用的组件,项目名,数据库,静态资源等。
  9 
 10 axf/urls.py:
 11  维护项目的URL路由映射,即定义当客户端访问时由哪个模块进行响应。
 12 
 13 axf/wsgi.py:
 14  定义WSGI的接口信息,主要用于服务器集成,通常本文件生成后无需改动。
Django目录介绍

    启动服务:python manager.py runserver [ip:port] 默认本机8000端口

    生成迁移:python manager.py makemigrations
    执行迁移:python mananger.py migrate

    settings中的DataBase模块,可以直接连接操作数据库Sqlite和MySQL

  1 
  2   1 'ENGINE':'django.db.backends.mysql', # 驱动
  3   2 'NAME':'school', # 数据库名
  4   3 'USER':'root', # 用户名
  5   4 'PASSWORD':'123', # 用户密码
  6   5 'HOST':'127.0.0.1', # 主机
  7   6 'PORT':'3306', # 端口
  8   7
DataBase模块参数

    安装sql驱动:pip install pymysql
    安装后还需要在__init__.py中添加初始化代码
        import pymysql
        pymysql.install_as_MySQLdb() # 导入驱动

    创建应用:python manager.py startapp XXX(应用名)

    将应用添加到settings.py.INSTALLED_APPS中使应用生效

    应用目录介绍:

  1 __init__.py:
  2  其中暂无内容,使得app成为一个包
  3 
  4 admin.py:
  5  管理站点模型的声明文件,默认为空
  6 
  7 apps.py:
  8  应用信息定义文件,在其中生成了AppConfig,该类用于定义应用名等数据
  9 
 10 models.py:
 11  添加模型层数据类文件
 12 
 13 views.py:
 14  定义URL相应函数(路由规则)
 15 
 16 migrations包:
 17  自动生成,生辰迁移文件的
 18 
 19 tests.py:
 20  测试代码文件
应用目录介绍

    创建响应函数连接应用路由到项目路由:

  1 首先我们在views.py中建立一个路由响应函数
  2 from django.http import HttpResponse
  3 
  4 def welcome(request):
  5 	return HttpResponse('HelloDjango');
  6 
  7 接着我们在urls中进行注册
  8 	from App import views
  9 	path('welcome/',views.welcome)
 10 
 11 基于模块化的设计,我们通常会在每个app中定义自己的urls
 12 
 13 在项目的urls中将app的urls包含进来
 14 	from django.conf.urls import include
 15  	path('welcome/',include('App.urls'))
 16 
连接应用路由到项目路由

    模板文件templates:

    客户端显示的实际上是经过处理的模板HTML

  1 模板文件实际上就是我们用HTML写好的页面
  2 
  3 在项目文件夹下创建模板文件夹templates
  4 在工程目录的需要注册
  5     settings中的TEMPLATES中的DIRS中添加
  6 	os.path.join(BASE_DIR,'templates')
  7 在模板文件夹中创建模板文件 XXX.html
  8 
  9 在views中去加载渲染模板
 10 1.from django.template import loader
 11 	template = loader.get_template('xxx')
 12 	return HttpResponse(template.render())
 13 
 14 2 return render(request,'xxx') #我喜欢这种
模板文件的处理

    模型介绍model:

    以学生班级为例,定义两个模型结构

  1 from django.db import models
  2 # 定义年级
  3 class Grade(models.Model):
  4 	g_name = models.CharField(max_length=10)
  5     	g_date = models.DateTimeField()
  6     	g_girlnum = models.IntegerField()
  7     	g_boynum = models.IntegerField()
  8     	isDelete = models.BooleanField()
  9 
 10 # 定义学生
 11 class Students(models.Model):
 12     	s_name = models.CharField(max_length=20)
 13     	s_gender = models.BooleanField(default=True)
 14     	s_age = models.IntegerField()
 15     	s_info = models.CharField(max_length=20)
 16     	isDelete = models.BooleanField(default=False)
 17     	# 关联外键>>理解原理需要学习数据库
 18     	s_grade = models.ForeignKey(Grade)
定义学生班级模型

    上面在settings中设置了MySQL的连接参数,这里就可以迁移数据到MySQL数据库

    生成迁移文件:python manager.py makemigrations
    执行迁移操作:python mananger.py migrate

测试数据模型:

  1 插入数据:
  2     {
  3     # 实例化对象:
  4         对象=类名; grade_one = Grade()
  5     # 对象属性赋值:
  6         对象.属性=值;grade_one.g_girlnum = 55
  7         .........
  8     对象.save()
  9     }
 10 
 11 查询:
 12     查询所有数据:类名.objects.all();Grade.objects.all()
 13     根据id查询一条数据:Grade.objects.get(pk=id)
 14     根据条件筛选:Grade.objects.filter(条件)
 15 
 16 修改数据:
 17     {
 18     # 查询要修改的对象:
 19         对象=类名.objects.查询方法;
 20         grade_one = Grade.objects.get(pk=id)
 21 
 22     # 对象属性赋值:
 23         对象.属性=值;grade_one.g_girlnum = 55
 24         .........
 25         对象.save()
 26     }
 27 
 28 删除数据:
 29     {
 30    # 查询要删除的对象:
 31         对象=类名.objects.查询方法;
 32         grade_one = Grade.objects.get(pk=id)
 33 
 34         对象.delete()
 35         grade_one.delete()
 36     }
数据测试增删改查
    创建班级数据:
  1 在App.views中
  2 
  3 # 导入包:
  4 from App.models import *
  5 from django.utils import timezone
  6 from datetime import *
  7 
  8 # 创建插入班级数据的函数:
  9 def add_grade(request):
 10     grade_one = Grade()
 11     grade_one.g_name = 'python9102'
 12     grade_one.g_date = datetime(year=9102, month=7, day=28)
 13     grade_one.g_girlnum = 55
 14     grade_one.g_boynum = 6
 15     grade_one.save()
 16     return HttpResponse('add OK')
 17 
 18 
插入班级数据

    创建学生数据:

  1 在views中创建插入学生数据的函数:
  2 
  3 def add_student(request):
  4     stu = Students()
  5     stu.s_name = 'rook'
  6     stu.s_age = 18
  7     stu.s_gender = True
  8     stu.s_info = '学渣2'
  9     stu.s_grade = Grade.objects.get(pk=2)
 10     stu.save()
 11     return HttpResponse('add {} OK'.format(stu.s_name))
插入学生数据

Django中获得关联对象集合:

    获取班级中的所有学生
    对象名.关联的类名小写_set.all()   
    grade_one.student_set.all()
---------------------------------------------------------------------------

数据从数据库到客户端的常用流程:

    客户端访问→路由urls↓

    urls根据规则调取views中对应方法↓

    views中的方法从models中取得数据↓

    views将数据渲染进templates中的对应的模型↓

    将渲染好的模板返回给客户端。。。点击查看模型图

Django模板语法:

  1 views中传参:
  2 def 函数名(request):
  3 
  4     XXX。。。处理逻辑。。。
  5 
  6     data = {
  7         key:value,
  8         。。。。。。
  9     }
 10     return render(request, '模板相对templates的路径', context=data)
 11 
 12 模板语法:
 13 直接取值用{{ key }}接受views函数中传过来的context的值
 14 表达式:{% for XX in key %}。。。等多种表达式
 15 	处理逻辑。。。
 16        {% endfor %}
 17 
 18 反向解析语法:{ % url 'name' 'p1' 'p2' %}?=
 19 ’get请求方式‘,'p1'和 'p2'是数据
模板语法
  1 将接收到的数据当成普通字符串处理还是当成HTML代码来渲染
  2 渲染成html:
  3 {{ code|safe}}
  4 
  5 {% autoescape off%}
  6 	code
  7 {% endautoescape %}
  8 
  9 不想渲染
 10 {% autoescape on%}
 11 	code
 12 {% endautoescape %}
HTML转义:
  1 某些恶意网站包含链接,表单,按钮,Js利用登陆用户在浏览器中的认证信息,进行非法操作,攻击服务,破坏数据
  2 
  3 在表单中添加
  4 {% csrf_token %}
  5 
  6 在settings中的中间件MIDDLEWARE中配置打开
  7     'django.middleware.csrf.CsrfViewMiddleware',
  8 
跨站请求伪造:
  1 extends 继承,写在开头位置
  2     {% extends  '父模板路径' %}
  3 
  4 关键字block:
  5     {% block XXX%}
  6           code
  7     {% endblock %}
  8 
  9 include:加载模板进行渲染
 10     格式{% include '模板文件' %}
 11 
模板继承:

参考文档:菜鸟教程||博客园-郭楷丰 详细图文随笔||CSDN参考博客

Django模型:

Django的model应用的是ORM模式

    ORM 全拼Object-Relation Mapping(对象关系映射);

  1 定义表信息:
  2 class Meta:
  3     db_table = xxx 定义数据表名,推荐使用小写字母
  4     ordering =[]
  5  升序ordering['id'],降序ordering['-id']
  6 
  7 过滤条件:
  8 all():返回所有数据
  9 filter():返回符合条件的数据
 10 exclude():过滤掉符合条件的数据
 11 order_by():排序
 12 values():一条数据就是一个字典,返回一个列表
 13 get():返回一个满足条件的对象,没有或多个会抛异常
 14 first():返回查询集中的第一个对象
 15 last():返回查询集中的最后一个对象
 16 count():返回当前查询集中的对象个数
 17 exists():判断查询集中是否有数据,有返回True
 18 可以连用
 19 
 20 在模型类中增加类方法去创建对象:
 21 @classmethoddef
 22 create(cls,name,age):
 23     自定义创建对象的方法。。。
 24 
 25 比较运算:
 26 语法:属性名称__比较运算符=值
 27 外键:属性名_id
 28 Student.objects.all()[0:5];取前5个,下标不能是负数
 29 filter(sname__contains='%');sname中包含%,开头加i不区分大小写
 30 startswith,endswith:以values开头或结尾,开头加i不区分大小写
 31 isnull,isnotnull:是否为空(sname__isnull=False)
 32 filter(pk__in=[2,4,6,8]);是否包含在范围内
 33 gt,gte,lt,lte:大于,大于等于,小于小于等于
 34 
 35 处理时间序列:
 36 filter(lasttime__year=2017)
 37 filter(pub_date__gt=date(1990,1,1));导入datetime.date
 38 
 39 跨关系查询:
 40 模型类名__属性名__比较运算符,实际上就是处理的数据库中的join
 41 grade = Grade.objects.filter(student__scontend__contains='楚人美')
 42 描述中带有'楚人美'这三个字的数据属于哪个班级
 43 
 44 聚合函数:
 45 使用aggregate()函数返回聚合函数的值
 46 Avg:平均值
 47 Count:数量
 48 Max:最大
 49 Min:最小
 50 Sum:求和
 51 Student.objects().aggregate(Max('sage'))
 52 
 53 F对象:
 54 可以使用模型的A属性与B属性进行比较
 55 grades = Grade.objects.filter(ggirlnum__gt=F('gboynum') )
 56 F对象支持算数运算
 57 grades = Grade.objects.filter(ggirlnum__gt=F('gboynum') +10 )
 58 
 59 Q对象:
 60 过滤器的方法中的关键参数,常用于组合条件
 61 年龄小于25
 62 Student.objects.filter(Q(sage__lt=25))
 63 Q对象语法支持  | (or), & (and), ~(取反)
 64 年龄大于等25
 65 Student.objects.filter(~Q(sage__lt=25))
 66 filter(Q(readcount__gt=20) | Q(id__lt=3))
Django模型常用方法:
  1 Django模型对应关系有:
  2 1:1(一对一)
  3 1:N(一对多)
  4 M:N(多对多)
  5 常见的几种数据关系,django都提供了很好的支持
  6 
  7 1 : 1
  8 使用models.OneToOneField()进行关联
  9 class Card(models.Model):
 10 	person = models.OneToOneField(Person,on_delete='CASCADE')
 11 
 12 绑定卡与人的一对一关系
 13 默认情况下,当人被删除的情况下,与人绑定的卡就也删除了
 14 可以使用on_delete进行调整
 15 on_delete:
 16 	models.CASCADE:默认值
 17 	models.PROTECT:保护模式
 18 	models.SET_NULL:置空模式
 19 	models.SET_DEFAULT:置默认值
 20 	models.SET();删除的时候重新动态指向一个实体
 21 访问对应元素:person.pcard
 22 
 23 1 : N
 24 使用models.ForeignKey关联
 25 删除时同 1 : 1
 26 获取对应元素  grade.student_set
 27 
 28 M : N
 29 使用models.
 30 删除会删除指定对象和关系表中的关系映射
 31 获取对应元素Goods和Buyer
 32 	goods. buyer_set
 33 	buyer. bgoods
 34 买家添加buyer.bgoods.add
 35 买家清空buyer.bgoods.clear
 36 买家移除buyer.bgoods.remove
 37 
 38 模型继承:
 39 在models中添加Meta,指定是否抽象,然后进行继承
 40 class Animal(models.Model):
 41 	xxx
 42 	class Meta:
 43 		abstract = True/False
 44 
 45 class Dog(Animal):
 46 	xxx
模型关系和继承:

模型关系参考:https://blog.csdn.net/duus_nabolun/article/details/83107276

Django数据查询时返回的是QuerySet对象;参考:Django ORM之QuerySet

自定义管理器参考:django之ORM介绍与基本使用↓↓

参考文档:菜鸟教程||django之ORM介绍与基本用法||django之ORM查询操作

Django-views:

Django中views模块是控制中心,几乎多有逻辑代码都在这个模块编写

HTTP请求中的两个核心对象:

    HttpRequest:请求对象

    HttpResponse:返回对象

Django在接收到http的请求后,会将请求生成一个WSGIRequest对象,并且作为参数传递给views函数的(request)参数,这个对象上包含着客户端上传的各种信息

视图函数处理完相关的逻辑后,也需要返回一个HttpResponseBase对象或者他的子类对象给浏览器。用的最多的子类对象是HttpResponse

WSGIResquest对象常用的属性和方法:(request)

  1 常用属性:
  2 path:请求的完整路径,不包含域名和参数
  3 method:请求的HTTP方法(GET或POST)
  4 GET:GET参数的类字典对象
  5 POST:POST参数的类字典对象
  6 FILES:上传文件的信息
  7 COOKIES:字典对象,key和value都是字符串
  8 session:字典对象,key和value都是字符串
  9 META:所有客户端发来的header信息
 10 
 11 常用方法:
 12 is_secure();是否采用Https协议
 13 is_ajax();是否采用ajax
 14 get_host;服务器的域名,+[端口号]
 15 get_full_path;返回完整的path,包括参数
 16 get_raw_url();获取完整url,(http://127.0.0.1:8000/index/)
 17 
 18 QueryDict对象:(类字典对象)
 19 get();获取指定key的值,没有则返回None
 20 getlist();key有多个值时使用,返回一个列表
WSGIResquest对象常用的属性和方法::

HttpResponse对象常用的属性和方法:

  1 content:返回的内容
  2 status_code:返回的http状态码
  3 write();写入数据到content中
  4 set_cookie:设置cookie
  5 delete-cookie:删除cookie
  6 content_type:返回数据的MIME类型默认text/html
  7   浏览器器会根据这个来显示数据常用的有:
  8   text/html:(默认的,HTML文件)
  9   text/plain:(纯文本)
 10   text/css:(css文件)
 11   text/javascript:(js文件)
 12   multipart/form-data:(文件提交)
 13   application/json:(json传输)
 14   application/xml:(xml文件)
HttpResponse对象常用的属性和方法:

参考文档:https://www.cnblogs.com/dxnui119/p/10434274.html

Django中cookie的使用:

  1 # 设置cookie,从服务器返回的response中设置
  2 response  = redirect(path);重定向到某个指定的路径下
  3 response.set_cookie(key,value,max_age=0)
  4 # 直接设置cookie的值和value
  5 # max_age是过期时间,0是默认,None是永久,接上数字是具体时间,用s做单位
  6 #如:response.set_cookie('name',person.name,max_age=3600)
  7 
  8 # 获取cookie,从客户端请求中获得
  9 name = request.COOKIE.get('name')
 10 response = render(request,'home.index',contex=({'name':name})
 11 return response
 12 
 13 # 清除cookie,从response清除
 14 response = redirect('namespace:name')
 15 response.delete_cookie('name')
cookie:

Django中session的使用:

  1 # 设置session
  2 #在setting中注册
  3 # INSTALLED_APPS:
  4 	'django.contrib.sessions'
  5 # MIDDLEWARE:
  6 	'django.contrib.sessions.middleware.SessionMiddleware'
  7 #默认是加上的,在request中设置session
  8 request.session['name'] = person.name
  9 request.session.set_expiry(60) # 设置过期时间,单位是s
 10 
 11 # 获取session,也是从request中获取
 12 name = request.session.get('name')
 13 
 14 # 删除session,在response中删除
 15 response.delete_cookie('sessionid') # 在客户端删除session
 16 del request.session['name'] # 在服务器端删除session
 17 request.session.flush() # 直接清除两端的session
session:

Django中token的使用:

  1 # 设置token,首先需要建立有关token字段的表格,在response中设置
  2 person.token = create_token() # create_token 是创造token的函数
  3 response.set_cookie('token',person.token)
  4 
  5 # 获取token,在request中获取token
  6 person.token = request.COOKIE.get('token')
  7 
  8 # 清除token,在response中清除
  9 response.delete_cookie('token')
 10 
 11 进行md5加密
 12 import hashlib
 13 def create_hash(password)
 14     md5 = hashlib.md5()
 15     md5.update(password.encode('utf-8'))
 16     return md5.hexdigest()
 17 
 18 uuid创建token
 19 import uuid
 20 token = str(uuid.uuid5(uuid.uuid4() ,'token'))
token:

urls:

带参数的url:可以指定参数类型

版本2.:path('marke/<int:typeid>/<childcid>/', views.market, name='market),

版本1.:url(r'^news/(?P<year>d{4})/(?P<month>d+)$',views.getNews)

验证码:

一般使用第三方包:Pillow

  1 安装:pip install Pillow
  2 核心:Image,ImageDraw,ImageFont
  3 
  4 绘制流程:
  5 import random
  6 from PIL import Image, ImageDraw, ImageFont, ImageFilter
  7 
  8 _letter_cases = "abcdefghjkmnpqrstuwxy"  # 小写字母,去除可能干扰的i,l,o,v,z
  9 _upper_cases = _letter_cases.upper()  # 大写字母
 10 _numbers = ''.join(map(str, range(3, 10)))  # 数字
 11 init_chars = ''.join((_letter_cases, _upper_cases, _numbers))
 12 
 13 def create_validate_code(size=(120, 30),
 14                          chars=init_chars,
 15                          img_type="GIF",
 16                          mode="RGB",
 17                          bg_color=(255, 255, 255),
 18                          fg_color=(0, 0, 255),
 19                          font_size=18,
 20                          font_type="Monaco.ttf", # 字体路径
 21                          length=4, # 验证码长度
 22                          draw_lines=True,
 23                          n_line=(1, 2),
 24                          draw_points=True,
 25                          point_chance = 2):
 26     '''
 27     @todo: 生成验证码图片
 28     @param size: 图片的大小,格式(宽,高),默认为(120, 30)
 29     @param chars: 允许的字符集合,格式字符串
 30     @param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,PNG
 31     @param mode: 图片模式,默认为RGB
 32     @param bg_color: 背景颜色,默认为白色
 33     @param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF
 34     @param font_size: 验证码字体大小
 35     @param font_type: 验证码字体,默认为 ae_AlArabiya.ttf
 36     @param length: 验证码字符个数
 37     @param draw_lines: 是否划干扰线
 38     @param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效
 39     @param draw_points: 是否画干扰点
 40     @param point_chance: 干扰点出现的概率,大小范围[0, 100]
 41     @return: [0]: PIL Image实例
 42     @return: [1]: 验证码图片中的字符串
 43     '''
 44 
 45     width, height = size # 宽, 高
 46     img = Image.new(mode, size, bg_color) # 创建图形
 47     draw = ImageDraw.Draw(img) # 创建画笔
 48 
 49     def get_chars():
 50         '''生成给定长度的字符串,返回列表格式'''
 51         return random.sample(chars, length)
 52 
 53     def create_lines():
 54         '''绘制干扰线'''
 55         line_num = random.randint(*n_line) # 干扰线条数
 56 
 57         for i in range(line_num):
 58             # 起始点
 59             begin = (random.randint(0, size[0]), random.randint(0, size[1]))
 60             #结束点
 61             end = (random.randint(0, size[0]), random.randint(0, size[1]))
 62             draw.line([begin, end], fill=(0, 0, 0))
 63 
 64     def create_points():
 65         '''绘制干扰点'''
 66         chance = min(100, max(0, int(point_chance))) # 大小限制在[0, 100]
 67 
 68         for w in range(width):
 69             for h in range(height):
 70                 tmp = random.randint(0, 100)
 71                 if tmp > 100 - chance:
 72                     draw.point((w, h), fill=(0, 0, 0))
 73 
 74     def create_strs():
 75         '''绘制验证码字符'''
 76         c_chars = get_chars()
 77         strs = ' %s ' % ' '.join(c_chars) # 每个字符前后以空格隔开
 78 
 79         font = ImageFont.truetype(font_type, font_size)
 80         font_width, font_height = font.getsize(strs)
 81 
 82         draw.text(((width - font_width) / 3, (height - font_height) / 3),
 83                     strs, font=font, fill=fg_color)
 84 
 85         return ''.join(c_chars)
 86 
 87     if draw_lines:
 88         create_lines()
 89     if draw_points:
 90         create_points()
 91     strs = create_strs()
 92 
 93     # 图形扭曲参数
 94     params = [1 - float(random.randint(1, 2)) / 100,
 95               0,
 96               0,
 97               0,
 98               1 - float(random.randint(1, 10)) / 100,
 99               float(random.randint(1, 2)) / 500,
100               0.001,
101               float(random.randint(1, 2)) / 500
102               ]
103     img = img.transform(size, Image.PERSPECTIVE, params) # 创建扭曲
104 
105     img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,边界加强(阈值更大)
106 
107     return img, strs
108 
109 在views中调用:
110 import io
111 from django.shortcuts import HttpResponse
112 from backend.utils import CheckCode
113 
114 def check_code(request):
115     """
116     获取验证码
117     :param request:
118     :return:
119     """
120     stream = io.BytesIO()
121     # 创建随机字符 code
122     # 创建一张图片格式的字符串,将随机字符串写到图片上
123     img, code = CheckCode.create_validate_code()
124     img.save(stream, "PNG")
125     # 将字符串形式的验证码放在Session中
126     request.session["CheckCode"] = code
127     return HttpResponse(stream.getvalue())
Pillow制作验证码:

富文本:

用处大约有两种
    1. 在后台管理中使用
    2. 在页面中使用,通常用来作博客

原文地址:https://www.cnblogs.com/yulincoco/p/11880914.html