Django3

作者: 文化银儿 | 来源:发表于2018-09-19 20:05 被阅读0次

    django分页,中间件,验证码使用指南

    前言

    在django中提供了很多的插件功能,有利于开发者快速开发,比如中间件,分页器等
    还提供了Pillow库,可以进行生成图片,用于登录的验证码图书设计。

    1. 中间件Middleware

    中间件:

    a) 是一个轻量级的,底层的插件,可以介入Django的请求和响应的过程(面向切面编程)

    b) 中间件的本质就是一个python类

    c) 面向切面编程(Aspect Oriented Programming)简称AOP,AOP的主要实现目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获取逻辑过程中各部分之间低耦合的隔离效果

    思考:

    什么是中间件,在settings.py中有很多的中间件,主要是用来做什么功能的呢,他们处理请求的url的过程在那些阶段呢,一般用来做那些数据的处理呢

    1.1 中间件的处理函数
    __init__:没有参数,在服务器响应的第一个请求的时候自动调用,用户确定时候启动该中间件
    
    process_request(self, request): 在执行视图前被调用,每个请求上都会被调用,不主动进行返回或返回HttpResponse对象
    
    process_view(self, request, view_func,view_args, view_kwargs):调用视图之前执行,每个请求都会调用,不主动进行返回或返回HttpResponse对象
    
    process_template_response(self, request, response):在视图刚好执行完后进行调用,每个请求都会调用,不主动进行返回或返回HttpResponse对象
    
    process_response(self, request, response):所有响应返回浏览器之前调用,每个请求都会调用,不主动进行返回或返回HttpResponse对象
    
    process_exception(self, request, exception):当视图抛出异常时调用,不主动进行返回或返回HttpResponse对象
    
    1.2 处理流程
    image.png
    1.3 自定义中间件流程
    1. 在工程目录下创建middleware目录

    2. 目录中创建一个python文件

    3. 在根据功能需求,创建切入需求类,重写切入点方法

    4.  from django.utils.deprecation import MiddlewareMixin
      
      
       class AuthUserMiddleWare(MiddlewareMixin):
      
           def process_request(self, request):
      
               print(‘xxxx’)
      
    5. 启动中间件,在settings中进行配置,MIDDLEWARE中添加middleware.文件名.类名

    image.png

    2.分页

    2.1 分页库Paginator的基本语法

    django提供了分页的工具,存在于django.core中

    Paginator: 数据分页工具
    Page:具体的某一页
    

    Paginator:

    对象创建: Paginator(数据集,每一页数据)
    

    属性:

    count  计算和
    
    num_pages: 页面总和
    
    page_range: 页码列表,从1开始
    

    方法:

    page(页码):获取的一个page对象,页码不存在则抛出invalidPage的异常
    
    2.2 常见错误
    invalidPage:page()传递无效页码
    
    PageNotAnInteger:Page()传递的不是整数
    
    Empty:page()传递的值有效,但是没有数据
    
    2.3 page对象

    page:

    对象获取,通过Paginator的page()方法获得
    

    属性:

    object_list: 当前页面上所有的数据对象
    number: 当前页的页码值
    paginator: 当前page关联的Paginator对象
    

    方法:

    has_next()   判断是否有下一页
    has_previous():  判断是否有上一页
    has_other_pages():  判断是否有上一页或下一页
    next_page_number();  返回下一页的页码
    previous_page_number(): 返回上一页的页码
    len(): 返回当前也的数据的个数
    
    2.4 Paginator对象和Page对象的关系

    如下有学生表,学生表中有25条数据,通过分页,每一个6条数据,去实现分页的功能

    image.png
    2.5 代码
    image.png

    3. 验证码

    在用户登录,注册以及一些敏感操作的时候,我们为了防止服务器被暴力请求,或爬虫爬取,我们可以使用验证码进行过滤,减轻服务器的压力。

    验证码需要使用绘图Pillow

    Pip install Pillow
    

    核心:

    image.ImageDraw.ImageFont
    

    绘制流程:

    background = (10,20,30)  RGB颜色
    
    初始化画布 
    image = Image.new(‘RGB’,(100,50), background)
    
    获取画布中画笔对象
    draw = ImageDraw.Draw(image, ‘RGB’)
    
    绘制验证码,随机四个
    导入字体文件path表示路径
    font = ImageFont.truetype(‘path’, size)
    
    fontcolor = (20,40,60)
    draw.text((x,y), ‘R’, font.fontcolor)  x,y是文字左上角坐标
    

    django上传图片使用指南

    前言

    在很多的应用场景中都需要上传图片,图片可以作为头像,文章的展示图片,或者web的banner图片等等,这时候就需要了解django中怎么去设置图片上传,并且实现该上传图片的功能。

    1. 安装PIL库

    pip install Pillow
    

    2. models中图片字段的定义

    在定义的学生的models中我们创建学生头像的字段,用于上传头像图片


    image.png

    注意:在指定字段为ImageField类型的时候,要指定upload_to参数,表示上传的图片的保存路径

    3. 配置上传图片的保存路径

    在工程目录下的settings.py中配置media_url和media_root路径

    image.png

    在工程目录下的urls.py文件中配置media的目录为静态目录

    先导入static的包:

    image.png

    设置media:

    image.png

    4. 在项目中创建media的目录

    image.png

    5. 实现保存图片

    image.png

    注意:上传的时候,需要指定enctype=‘multipart/form-data’

    6. 页面中解析上传的图片信息

    在数据库中用于保存图片的字段s_content的字段中存的是media下的upload/xxx.jpg地址,所以在页面解析的时候,需要加上media的目录,这样才能解析到图片在服务器中的路径

    image.png

    django项目对接富文本编辑器kindeditor的使用

    前言

    在Django中经常使用富文本编辑来编辑文本内容。富文本编辑器有很多可以选择,比如baiduEditor,tinymce,kindeditor等等。在此我选择使用kindeditor富文本编辑器,KindEditor 使用 JavaScript 编写,可以无缝地与 Java、.NET、PHP、ASP 等程序集成,很适合做网站的文本编辑器来使用。

    1. kindeditor下载与配置

    下载 KindEditor 最新版本,下载之后打开 examples/index.html 就可以看到演示。

    步骤1: 下载传送门地址

    步骤2: 将下载的kindeditor解压,并删除无用的asp、jsp、php等配置文件夹。

    步骤3: 将kindeditor文件夹拷贝放在static中

    如:

    image.png

    2. Django中配置

    要使用kindeditor富文本编辑器需要在settings.py文件中配置静态static解析路径,以及media文件解析路径。并且在页面中进行相关js的加载,和上传路径的指定等。

    2.1 在settings.py中配置如下参数:

    STATIC_URL = '/static/'
    # 配置static的路径
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR, 'static')
    ]
    
    MEDIA_URL = '/media/'
    # 配置media的路径
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
    

    2.2 页面中加载富文本编辑器,引入js,定义uploadJson上传地址,实例化富文本输入框

    步骤1:引入js, 定义上传图片等文件的地址

    <script type="text/javascript" src="{% static 'kindeditor/kindeditor-all.js' %}"></script>
        <script type="text/javascript" src="{% static 'kindeditor/lang/zh-CN.js' %}"></script>
        <script type="text/javascript">
            KindEditor.ready(function(K) {
                    window.editor = K.create('#editor_id',{
                        uploadJson:'/util/upload/kindeditor'
                    });
            });
        </script>
    

    uploadJson参数为:'/util/upload/kindeditor',该URL实现了上传文件的方法。该URL对应的视图函数,在步骤3中定义。

    步骤2: 定义富文本编辑器的对象

    <textarea id="editor_id" name="content">
    
    </textarea>
    

    步骤3:定义uploadJson实现的方法

    a)在urls.py中定义处理上传文件的URL规则

    from utils.upload_image import upload_image
    
     # kindeditor编辑器上传图片地址
    re_path(r'^util/upload/(?P<dir_name>[^/]+)$', upload_image, name='upload_image'),
    

    b)在utils中定义upload_images文件,并定义upload_image函数

    # -*- coding: utf-8 -*-
    from django.http import HttpResponse
    from django.conf import settings
    from django.views.decorators.csrf import csrf_exempt
    import os
    import uuid
    import json
    import datetime as dt
    


    @csrf_exempt
    def upload_image(request, dir_name):
    ##################
    # kindeditor图片上传返回数据格式说明:
    # {"error": 1, "message": "出错信息"}
    # {"error": 0, "url": "图片地址"}
    ##################
    result = {"error": 1, "message": "上传出错"}
    files = request.FILES.get("imgFile", None)
    if files:
    result =image_upload(files, dir_name)
    return HttpResponse(json.dumps(result), content_type="application/json")


    #目录创建
    def upload_generation_dir(dir_name):
    today = dt.datetime.today()
    dir_name = dir_name + '/%d/%d/' %(today.year,today.month)
    if not os.path.exists(settings.MEDIA_ROOT + dir_name):
    os.makedirs(settings.MEDIA_ROOT + dir_name)
    return dir_name

    # 图片上传
    def image_upload(files, dir_name):
        #允许上传文件类型
        allow_suffix =['jpg', 'png', 'jpeg', 'gif', 'bmp']
        file_suffix = files.name.split(".")[-1]
        if file_suffix not in allow_suffix:
            return {"error": 1, "message": "图片格式不正确"}
        relative_path_file = upload_generation_dir(dir_name)
        path=os.path.join(settings.MEDIA_ROOT, relative_path_file)
        if not os.path.exists(path): #如果目录不存在创建目录
            os.makedirs(path)
        file_name=str(uuid.uuid1())+"."+file_suffix
        path_file=os.path.join(path, file_name)
        file_url = settings.MEDIA_URL + relative_path_file + file_name
        open(path_file, 'wb').write(files.file.read()) # 保存图片
        return {"error": 0, "url": file_url}
    

    3. 文件上传media文件中的展示

    image.png

    日志使用指南

    前言

    在django中对日志记录提供了很好的支持,日志文件在开发环境中以及在线上环境或者在测试环境中都可以很好的反应程序的执行情况,以及出现bug的时候,准确的定位bug的位置,请求方法,错误原因等。所以说日志对于程序猿来说是一个开发者必备的必须了解且精通的东西。一下就来大致讲解下日志的配置以及使用,以及调试等

    1. 日志logging模块

    logging模块可以收集记录错误,警告等调试信息,在程序中可以捕获这些信息,并且甚至可以将错误的重要信息等都可以通过邮件发送给开发者

    1.1 logging的组成
    Loggers
    
    Handlers
    
    Filters
    
    Formatters
    
    1.1 Loggers

    Logger 为日志系统的入口。每个logger 是一个具名的容器,可以向它写入需要处理的消息。

    每个logger 都有一个日志级别。日志级别表示该logger 将要处理的消息的严重性。

    Python 定义以下几种日志级别:

    DEBUG:用于调试目的的底层系统信息
    
    INFO:普通的系统信息
    
    WARNING:表示出现一个较小的问题。
    
    ERROR:表示出现一个较大的问题。
    
    CRITICAL:表示出现一个致命的问题。
    

    日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET

    1.2 Handlers

    Handler 决定如何处理logger 中的每条消息。它表示一个特定的日志行为。

    与logger 一样,handler 也有一个日志级别。<u>如果消息的日志级别小于handler 的级别,handler 将忽略该消息。</u>

    Logger 可以有多个handler,而每个handler 可以有不同的日志级别。

    1.3 Filters

    Filter 用于对从logger 传递给handler 的日志记录进行额外的控制。

    1.4 Formatters

    日志记录需要转换成文本。

    Formatter 表示文本的格式。Fomatter 通常由包含日志记录属性的Python 格式字符串组成;

    你也可以编写自定义的fomatter 来实现自己的格式。

    如下展示了formatters格式:


    image.png

    2.配置logging模块

    在settings.py文件中配置

    2.1 创建日志所在目录
    image.png
    2.2 定义LOGGING的格式
    image.png
    2.2 定义handler的格式
    image.png
    2.2 定义loggers的格式
    image.png

    注意:loggers的level的级别一定要大于handlers的级别,否则handlers会忽略掉该信息的。

    3. 使用logging打印日志

    image.png

    4. 查看log文件中日志打印的记录

    image.png

    celery使用指南

    前言

    来着官网中的英文解释:

    Celery is a simple, flexible, and reliable distributed system to process vast amounts of messages.

    It’s a task queue with focus on real-time processing, while also supporting task scheduling.

    翻译:Celery是一个简单,灵活且可靠的分布式系统,用于处理大量的消息。

    这是一个专注于实时处理的任务队列,同时也支持任务调度。

    官网地址: 地址

    1. 高级信息队列协议

    AMQP,即AdvancedMessage Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。

    2. 生产者与消费者模式概念

    什么是生产者与消费者模式呢,某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。

    单单抽象出生产者和消费者,还够不上是生产者消费者模式。该模式还需要有一个缓冲区处于生产者和消费者之间,作为一个中介。生产者把数据放入缓冲区,而消费者从缓冲区取出数据

    image.png

    3. celery的架构

    Celery的架构由三部分组成,消息中间件(message broker),任务执行单元(worker)和任务执行结果存储(task result store)组成。

    image.png

    <b>消息中间件(message broker)</b>:Celery本身不提供消息服务,但是可以方便的和第三方提供的消息中间件集成。包括,<b>RabbitMQ, Redis</b>, MongoDB ,SQLAlchemy等,其中rabbitmq与redis比较稳定,其他处于测试阶段。

    <b>任务执行单元(worker)</b>:Worker是Celery提供的任务执行的单元,worker并发的运行在分布式的系统节点中。

    <b>任务结果存储(result store)</b>:result store用来存储Worker执行的任务的结果,支持AMQP,redis,mongodb,mysql等主流数据库。

    4. 插件安装

    4.1 安装celery,redis以及相关的依赖包
    pip install -U celery[redis]
    

    配置非常简单,只需要设置 Redis 数据库的位置:

    BROKER_URL = 'redis://localhost:6379/0'

    URL 的格式为:

    redis://:password@hostname:port/db_number

    4.2 创建官网上简单的celery案例

    案例中使用redis作为信息中间件broker:

    image.png

    代码解释:

    1. 直接初始化Celery对象,指定信息中间件,使用redis进行链接

    2. 使用celery对象的task装饰我们需要异步的函数

    简单的两步就实现了celery的异步函数

    执行命令解释:

    启动一个随时监听异步任务处理函数的worker,使用命令celery -A xxxx模块名 worker --loglevel=info,其中该命令中-A参数表示我们创建的py文件为tasks.py文件的话,则celery -A tasks worker --loglevel=info

    执行异步函数:

    进入python环境进行测试功能,使用delay()来会掉我们创建的任务:

    image.png

    注意:

    采用delay()函数来创建我们的回调函数,如果直接使用add(1,2)就和普通的函数没有任何区别了。

    4.3 查看redis中存入的结果值

    当执行了delay()方法以后,都会在控制台看到打印了存入redis中的key的信息

    先查看一下,当我们调用delay()回调任务的时候,打印的结果:

    image.png

    再来查看一下,redis中的key值,以及对应的value值的结果。value值为celery存入的结构化对象,需要使用celery的api获取这些值。

    image.png

    5. django中配置celery

    restful使用指南1

    前言

    REST是所有Web应用都应该遵守的架构设计指导原则。

    Representational State Transfer,翻译是”表现层状态转化”。

    REST核心: <b><font style="color:red;">资源, 状态转移, 统一接口 </font></b>

    <b>资源:</b> 是REST最明显的特征,是指对某类信息实体的抽象,资源是服务器上一个可命名的抽象概念,资源是以名词为核心来组织的,首先关注的是名词。

    <b>状态转移:</b> 是指客户端痛服务端进行交互的过程中,客户端能够通过对资源的表述,实现操作资源的目的

    <b>统一接口:</b> REST要求,必须通过统一的接口来对资源执行各种操作。对于每个资源只能执行一组有限的操作。 比如,客户端通过HTTP的4个请求方式(POST, GET, PUT, PATCH)来操作资源,也就意味着不管你的url是什么,不管请求的资源是什么但操作的资源接口都是统一的。

    GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT(PATCH)用来更新资源,DELETE用来删除资源。

    1. api定义规范

    http://xxx.com/api/
    

    2. 资源

    在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的"集合"(collection),所以API中的名词也应该使用复数。

    举例来说,有一个API提供动物园(zoo)的信息,还包括各种动物和雇员的信息,则它的路径应该设计成下面这样。

    https://api.example.com/v1/zoos
    
    https://api.example.com/v1/animals
    
    https://api.example.com/v1/employees
    

    3. http请求方式

    GET(SELECT):从服务器取出资源(一项或多项)
    
    POST(CREATE):在服务器新建一个资源
    
    PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)
    
    PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)
    
    DELETE(DELETE):从服务器删除资源
    

    例子:

    GET /zoos:列出所有动物园
    
    POST /zoos:新建一个动物园
    
    GET /zoos/ID:获取某个指定动物园的信息
    
    PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
    
    PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
    
    DELETE /zoos/ID:删除某个动物园
    
    GET /zoos/ID/animals:列出某个指定动物园的所有动物
    
    DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物
    

    4. filter过滤

    ?page=2&per_page=100:指定第几页,以及每页的记录数。
    
    ?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
    
    ?animal_type_id=1:指定筛选条件
    

    5. 状态码

    服务端向用户返回请求api的结果,在结果中包含了status codes 状态码的,可以通过状态码去判断请求api的状态是成功还是失败

    200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
    
    201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
    
    202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
    
    204 NO CONTENT - [DELETE]:用户删除数据成功。
    
    400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
    
    401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
    
    403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
    
    404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
    
    406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
    
    410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
    
    422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
    
    500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
    

    6. 错误处理

    如果状态码是4xx,就应该向用户返回出错信息。一般来说,返回的信息中将error作为键名,出错信息作为键值即可。

    {
        error: '错误信息'
    }
    

    7. django中使用restful

    pip install djangorestframework==3.4.6
    
    
    pip install django-filter  # Filtering support
    

    8. settings.py配置的修改

    在工程目录中的settings.py文件的INSTALLED_APPS中需要添加rest_framework

    image.png

    9. 定义url

    image.png

    10. 简单的CRUD

    具体的详细介绍在地址

    导入相关的信息:

    from rest_framework import mixins, viewsets
    
    image.png

    CRUD对应的增删改查:

    增: POST http://127.0.0.1:8080/stu/addStu/
    
    删: DELETE http://127.0.0.1:8080/stu/addStu/1/
    
    改: UPDATE http://127.0.0.1:8080/stu/addStu/1/
    
    查: GET http://127.0.0.1:8080/stu/addStu/1/
    

    用户权限,用户角色使用指南

    前言

    RBAC(Role-Based Access Control,基于角色的访问控制)就是用户通过角色与权限进行关联。简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。在这种模型中,用户与角色之间,角色与权限之间,一般者是多对多的关系。

    如下就是一个简单的权限设计模式,其中包含了用户表,角色表,权限表。

    image.png

    1. 定义模型

    用户表:

    class Users(models.Model):
    
        username = models.CharField(max_length=10)
        password = models.CharField(max_length=200)
        ticket = models.CharField(max_length=30)
        create_time = models.DateTimeField(auto_now_add=True)
        login_time = models.DateTimeField(auto_now=True)
    
        class Meta:
            db_table = 'user'
    

    权限表:

    class RolePermission(models.Model):
        p_en = models.CharField(max_length=10)  # 权限英文名称
        p_name = models.CharField(max_length=10)  # 权限中文名称
    
        class Meta:
            db_table = 'role_per'
    

    角色表:

    class Role(models.Model):
        r_name = models.CharField(max_length=10)  # 角色名称
        u = models.OneToOneField(Users)  # 关联的用户
        r_p = models.ManyToManyField(RolePermission)  # 多对多关联的权限
    
        class Meta:
            db_table = 'role'
    

    2. 简单的查询

    # 1) 查询某某用户具备那些权限
    # 2)判断某一个用户是否有某一个权限
    
    from uAuth.models import Users, RolePermission, Role
    


    def Test(request):

        user = Users.objects.get(id=1)
        u = user.role.r_p.filter(p_name='添加权限')
        print(u)
        return HttpResponse('查询成功')
    

    3. 插入数据库的数据

    image.png

    4. 通过用户的权限,在页面中动态的加载菜单

    在登录的方法中,我们定义了中间件,如果用户登录成功,我们会将当前登录的用户的user信息赋值给request.user,那么我们在页面中就可以通过user去获取到权限的信息了。

    具体通过user获取permission的列表是一下写法:

    user.role.r_p.all
    

    修改以下菜单页面:

    <dl class="system_log">
        {% for permission in user.role.r_p.all %}
            {% ifequal permission.p_en 'GRADELIST' %}
                <dt>
                    <img class="icon1" src="/static/img/coin03.png" /><img class="icon2"
                        src="/static/img/coin04.png" /> 班级管理<img class="icon3"
                        src="/static/img/coin19.png" /><img class="icon4"
                        src="/static/img/coin20.png" />
                </dt>
                <dd>
                    <img class="coin11" src="/static/img/coin111.png" /><img class="coin22"
                        src="/static/img/coin222.png" />
                    <a class="cks" href="{% url 'app:grade' %}"
                        target="main">班级列表</a><img class="icon5" src="/static/img/coin21.png" />
                </dd>
            {% endifequal %}
        {% endfor %}
        {% for permission in user.role.r_p.all %}
            {% ifequal permission.p_en 'GRADEADD' %}
                <dd>
                    <img class="coin11" src="/static/img/coin111.png" /><img class="coin22"
                        src="/static/img/coin222.png" />
                    <a class="cks" href="{% url 'app:addgrade' %}"
                        target="main">班级添加</a><img class="icon5" src="/static/img/coin21.png" />
                </dd>
            {% endifequal %}
        {% endfor %}
    </dl>
    <dl class="system_log">
        {% for permission in user.role.r_p.all %}
            {% ifequal permission.p_en 'STUDENTLIS' %}
                <dt>
                    <img class="icon1" src="/static/img/coin03.png" /><img class="icon2"
                        src="/static/img/coin04.png" /> 学生管理<img class="icon3"
                        src="/static/img/coin19.png" /><img class="icon4"
                        src="/static/img/coin20.png" />
                </dt>
                <dd>
                    <img class="coin11" src="/static/img/coin111.png" /><img class="coin22"
                        src="/static/img/coin222.png" />
                    <a class="cks" href="{% url 'app:student' %}"
                        target="main">学生列表</a><img class="icon5" src="/static/img/coin21.png" />
                </dd>
            {% endifequal %}
        {% endfor %}
        {% for permission in user.role.r_p.all %}
            {% ifequal permission.p_en 'STUDENTADD' %}
                <dd>
                    <img class="coin11" src="/static/img/coin111.png" /><img class="coin22"
                        src="/static/img/coin222.png" />
                    <a class="cks" href="{% url 'app:addstu' %}"
                        target="main">添加学生</a><img class="icon5" src="/static/img/coin21.png" />
                </dd>
            {% endifequal %}
        {% endfor %}
    </dl>
    

    restful使用指南2

    1. 修改响应的结构

    1.1 修改settings.py中的返回数据结构的配置信息
    image.png

    注意:定义default_renderer_classes参数,指定render的时候使用我们自定义的CustomJsonRender的类方法

    1.2 重构JSONRenderer下的render方法

    该方法继承了JSONRenderer并且重构了render方法,修改了返回的数据结构


    image.png image.png

    2. 异常的响应的结构

    自定义异常处理,一定需要继承from rest_framework.exceptions import APIException
    中的APIException,在编写自己的异常处理的方法

    image.png

    3. PATCH请求,传入空置处理

    3.1 空置处理

    该patch请求中,我们想要修改id为3的学生的姓名,但是姓名我们传递一个空置,查看返回结果如下:


    image.png
    3.2 修改

    在serializer中定义s_name的序列化,指定错误的信息,为空的话,提示响应的错误信息

    image.png

    4. 页面异步提交api接口请求,并且在前端通过js刷新页面

    4.1. 创建实例
    4.1.1 后端业务逻辑处理

    创建url,定义register,创建serializer_class等

    image.png image.png
    4.2 前端ajax请求get获取数据并刷新
    image.png
    4.3 前端ajax请求delete删除数据
    image.png image.png
    4.4 直接放入ajax更新删除获取信息的代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>展示所有学生的信息</title>
    <script type="text/javascript" src="/static/js/jquery.min.js"></script>
    <script type="text/javascript">
        $(function(){
            $('#showStus').click(function(){
                $.get('/stu/student/', function(msg){
                    s = '<table><tr><td>ID</td><td>姓名</td><td>地址</td><td>操作</td></tr>'
                    for(var i=0; i<msg.length; i++){
                        s += '<tr><td>' + msg[i].id + '</td>\
                        <td>' + msg[i].s_name + '</td>\
                        <td>' + msg[i].s_tel + '</td><td>\
                        <a href="javascript:;" onclick="stu_update(' + msg[i].id + ')">编辑</a>|\
                        <a href="javascript:;" onclick="del_stu(' + msg[i].id + ')">删除</a></td></tr>'
                    }
                    s += '</table>'
                    $('#div_stus').html(s)
                }, 'json');
            });
        });
    
        function del_stu(i){
            csrf = $('input[name="csrfmiddlewaretoken"]').val()
            $.ajax({
                url:'/stu/student/' + i,
                type:'DELETE',
                headers:{'X-CSRFToken': csrf},
                dataType:'json',
                success: function(msg){
                    alert('删除成功');
                },
                error: function(msg){
                    console.log(msg)
                },
            });
        };
    
        function stu_update(i){
            s = 'ID: <input type="hidden" name="id" value="' + i + '">\
            姓名:<input type="text" name="s_name" id="s_name"> \
            电话:<input type="text" name="s_tel" id="s_tel">\
            <input type="button" value="提交" onclick="update(' + i + ')">'
    
            $('#div_add').html(s)
        };
    
        function stu_add(){
            s = '姓名:<input type="text" name="s_name" id="s_name"> \
            电话:<input type="text" name="s_tel" id="s_tel">\
            <input type="button" value="提交" onclick="add()">'
    
            $('#div_add').html(s)
        };
    
    function update(i){
        csrf = $('input[name="csrfmiddlewaretoken"]').val()
        s_name = $('#s_name').val()
        s_tel = $('#s_tel').val()
        $.ajax({
            url: '/stu/student/' + i + '/',
            type: 'PATCH',
            dataType: 'json',
            headers:{'X-CSRFToken': csrf},
            data:{'s_name':s_name, 's_tel':s_tel},
            success: function(msg){
                console.log(msg)
            },
            error: function(msg){
                console.log(msg)
            },
        });
    }
    
    function add(){
        csrf = $('input[name="csrfmiddlewaretoken"]').val()
        s_name = $('#s_name').val()
        s_tel = $('#s_tel').val()
        $.ajax({
            url: '/stu/student/',
            type: 'POST',
            dataType: 'json',
            headers:{'X-CSRFToken': csrf},
            data:{'s_name':s_name, 's_tel':s_tel},
            success: function(msg){
                console.log(msg)
            },
            error: function(msg){
                console.log(msg)
            },
        });
    }
    </script>
    
    </head>
    <body>
    {% csrf_token %}
    <input id="showStus" value="获取所有学生的信息" type="button"></input>
    <div id="div_stus">
    
    </div>
    <div id="div_add"></div>
    <a href="javascript:;" onclick="stu_add()">添加</a>
    </body>
    </html>
    

    5. 跨域请求

    5.1 什么是跨域

    同源:是指相同的协议、域名、端口,三者都相同才属于同源。

    同源策略:浏览器处于安全考虑,在全局层面禁止了页面加载或执行与自身来源不同的域的任何脚本,站外其他来源的脚本同页面的交互则被严格限制。

    跨域由于浏览器同源策略,凡是发送请求url的协议、域名、端口三者之间任意一与当前页面地址不同即为跨域

    6. rest中的坑

    在实际的django项目中,我们经常需要使用到用户表,但是基于django提供的User表的字段有限,开发者一般都不会使用django提供的User模型,而自己创建User模型,并且基于登录注册的功能,也都会自己去实现,而不会使用django提供的登录注册功能。

    重点坑:在我们使用自定义的User模型进行用户的登录以及注册的时候,我们使用自定义的中间件进行对用户进行验证,如果验证通过了,就将当前登录的用户User对象绑定在request中,即request.user = user。这个时候坑就出现了,当我们使用restframework去写api接口的时候,会出现权限认证错误,如下提示:

    image.png

    经过分析,可以判断是rest需要进行身份验证,所有我们在settings.py中设置rest的api接口不需要进行authentication的验证,具体配置如下:

    image.png

    restful使用指南3

    1. 分页

    修改settings.py配置文件,增加分页的配置信息

    image.png

    结果:

    image.png

    注意:在结果在data对应的value值中,有一个count的key,表示返回数据有3条,next表示下一个的url,previous表示上一页的url。

    2. 过滤

    修改settings.py配置文件,增加filter过滤的信息

    2.1 安装过滤的库

    pip install django-filter
    

    2.2 配置settings.py的信息

    配置DEFAULT_FILTER_BACKENDS

    image.png

    2.3 views中指定filter_class

    image.png

    2.4 编写filter_class过滤信息

    image.png

    2.5 实现方法

    2.5.1 查询学生的姓名中包含王的学生

    使用filter_class进行过滤筛选:

    http://127.0.0.1:8080/stu/student/?name=王
    

    不使用filter_class进行筛选:

    image.png
    2.5.2 查询学生的创建时间在2018年1月1号到2018年6月1号的学生信息

    使用filter_class进行过滤筛选:

    http://127.0.0.1:8080/stu/student/?create_min=2018-02-01&create_max_max=2018-0-01
    

    不使用filter_class进行筛选:

    image.png
    2.5.3 查询状态为休学的学生信息
    http://127.0.0.1:8080/stu/student/?status=LEAVE_SCH
    
    2.5.4 查询所有的学生,按照id从大到小排序
    image.png

    2.6 拓展

    image.png

    相关文章

      网友评论

        本文标题:Django3

        本文链接:https://www.haomeiwen.com/subject/xqcwnftx.html