美文网首页
自定义验证类,ajax,中间件

自定义验证类,ajax,中间件

作者: 快去学习不然怎么去看aimer | 来源:发表于2019-09-25 21:03 被阅读0次

    自定义验证类

    在views.py中

    #由于django只验证用户名,密码,因此需要自定义
    class CustomBackend(ModelBackend):
        def authenticate(self, request, username=None, password=None, **kwargs):
            try:
                user = User.objects.get(
                    Q(username=username) |
                    Q(email=username ) |
                    Q(mobile = username)              
                )
                if user.check_password(password):
                    return user
            except Exception:
                return None
    #值得注意的地方,用于验证的字段必须不能重复,而且不能为空
    

    小技巧

    测试单个文件

    #单独测试某模块的功能
    
    
    import  os, sys
    # 获取到项目的根目录
    PROJECT_ROOT = os.path.dirname(os.path.abspath('__file__'))  #根据具体的文件位置改变
    
    # 把项目的根目录放到 sys.path 中
    sys.path.insert(0, PROJECT_ROOT)
    
    # 设置环境变量
    os.environ["DJANGO_SETTINGS_MODULE"] = 'qf01.settings'
    import django
    django.setup()
    
    if __name__ == "__main__":
        """在这里写自己的测试代码"""
        # 导入 映射类
        from users.models import UsersProfile
    
        # 获取表中的第一条数据
        user = UsersProfile.objects.all()[1]
        print(user.username, user.mobile)
    

    前后端分离---后端发送JSON数据

    from django.http import JsonResponse,HttpResponse
    from django.views import View
    from django.core import serializers
    from users.models import UsersProfile
    from cmdb.models import Server
    
    
    class ApiView(View):
        def get(self, request):
            users = Server.objects.values()
            return JsonResponse(list(users), safe=False)       
    #json数据里直接为得到的数据的字典,safe为必须字段
    
    
    class ApiViewTwo(View):
        def get(self, request):
            users = UsersProfile.objects.all()
            data = serializers.serialize('json',users)
            return HttpResponse(data)       
    #json数据为字典嵌套字典,字段为某一vales
    

    前后段分离---urls

    from django.urls import path
    from .  import views
    from django.views.generic import TemplateView
    
    
    app_name = "api"
    urlpatterns = [
        path('users-json/', views.ApiView.as_view(), name="user2json"),
        path('users-json2/', views.ApiViewTwo.as_view(), name="user2json2"),
        path('users-json3/', views.ApiViewThree.as_view(), name="jQuery"),
        path('server-vue/', TemplateView.as_view(template_name="api/VueAxios.html"), name='VueAxios'), #不需要在views中写,直接返回页面
    ]
    
    #使用template可以不要在views.py中写class,直接返回页面,因此无法做到登陆用户验证
    

    前后端分离---前端接收

    方式一

    {%  extends 'putbase.html' %}
    
    {% block content %}
    <button  type="submit" id = 'btn'  class="btn btn-success" >获取数据</button>
    <h2 id="title"></h2>
    <table class="table table-bordered table-hover">
        <thead>
            <tr>
                <th>id</th>
                <th>主机名</th>
                <th>操作系统</th>
                <th>物理 CPU 颗数</th>
            </tr>
        </thead>
        <tbody  id = "mess">
    
        </tbody>
    </table>
    {% endblock %}
    
    {%  block script %}
    <script>
        $(function(){
            let title_tg = $("#mess")
            $("#btn").on("click",function(){
                $.ajax({                           #ajax的固定格式
                    url: "{% url  'api:user2json' %}",     #数据来源
                    type: 'GET',                                   #请求数据的方式
                    dataType: 'json',                             #数据格式
                    success:function (res) {                 #若请求成功则执行
                        for (let i of res){
                            title_tg.append(`<tr>                #将循环得到的数据添加到tbody中,使用append方法不 
                                <td>${i.id}</td>                     #会覆盖上一条数据,但是每点击一次请求,就会get
                                <td>${i.host_name}</td>       #一次。
                                <td>${i.os_name}</td>
                                <td>${i.physical_count}</td>         #`<>${}<>`添加标签
                            </tr>`)
                            // title_tg.html()                                    #将`<>${}<>`的标签添加到html中
                        }  
                    },
                });
            })
        })
        
    </script>
    {% endblock %} 
    

    方式二

    #使用vue与axios结合的方式
    {% extends 'putbase.html' %}
    
    {% block content %}
    <div id="app">
        {% verbatim %}
        <button id="btn" class="btn btn-success">获取数据</button>
        <h2>Vue出现{{ msg }}</h2>
        <table class="table table-bordered table-hover">
            <thead>
                <tr>
                    <th>id</th>
                    <th>主机名</th>
                    <th>内核</th>
                    <th>物理 CPU 颗数</th>
                </tr>
            </thead>
            <tbody id="tbody">
                <tr v-for="item in  servers" :key="">      #vue循环
                    <td>{{ item.id }}</td>
                    <td>{{ item.host_name }}</td>
                    <td>{{ item.kernel }}</td>
                    <td>{{ item.physical_count }}</td>
                </tr>
            </tbody>
        </table>
        {% endverbatim %}
    </div>
    
    
    {% endblock %}
    
    
    {% block script %}
    
    <script>
        var app = new Vue({
            el: "#app",
            data: {
                msg: 'hello',
                servers: ''
            },
            mounted() {
                axios.get(
                    "{% url 'api:user2json' %}",
                ).then(
                    res => {
                        this.servers = res.data;
                    });
            },
        })
    
    </script>
    
    {% endblock %}
    

    将vue,axios,bootstrap,加载到本地文件中

    #在项目主目录里建立static目录
    /django2-demo/roudjo/statics/
    ├── bootstrap
    │   ├── css
    │   ├── fonts
    │   └── js
    └── js
        ├── axios.min.js
        └── vue.min.js
    
    
    #在setttings.py中
    STATIC_URL = '/static/'
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR, 'statics'),  # 最后有英文的逗号
    ]
    
    #在前端页面中
    ##############################################################
    方式一:
    href="/static/bootstrap/css/bootstrap.min.css"   
       #/static为STATIC_URL的指定名字  后面为项目文件名字
    
    ###############################################################
    方式二:
    {% load staticfiles %}   #在<head>是上面添加
    src="{% static 'js/axios.min.js' %}"   #static同样为STATIC_URL的指定名字 ,后面为项目文件名字
    

    中间件

    http的请求通过的顺序


    请求顺序.png

    自定义中间件

    #在项目主目录下建立中间件目录
    /django2-demo/roudjo/MyMiddieware/
    ├── __pycache__
    └── rejectip.py
    
    #在rejectip.py中
    from django.shortcuts import HttpResponse
    import time
    
    
    # 时间范围 3 秒
    REJ_SECOND = 5
    
    # 限定访问次数
    REJ_LIMIT = 3
    
    # 封闭时长
    REJ_TIME = 10
    
    # IP 列表
    REJ_IP = {}
    info = {
        'count': '3 秒内范围的次数',
        'access_time': '访问时间',
        'rejected': '拒绝时长',
    }
    
    
    def reject_ip(ip):
        if ip not in  REJ_IP:
            REJ_IP[ip] = {
                'count': 1,
                'access_time': int(time.time()),
                'rejected': None
                }
            return None
        # 程序走到这里时,增加访问次数 1 次
        REJ_IP[ip]['count'] += 1
    
        # 判断是否在 3 秒之内
        if time.time() < REJ_IP[ip]['access_time'] + 3:
                # 判断访问次数合法
                if REJ_IP[ip]['count'] > REJ_LIMIT:
                    REJ_IP[ip]["rejected"] = int(time.time())
                    print("访问次数首次超限:",REJ_IP[ip]['count'])
                    return True
                print("有了:",REJ_IP)
    
        # 程序走的这里是 3 秒之外
        else:
                print("目的访问次数:",REJ_IP[ip]['count'])
                rejected = REJ_IP[ip]["rejected"]
                if rejected and time.time() < REJ_IP[ip]["rejected"] + REJ_TIME:
                    print("访问信息",REJ_IP[ip] )
                    return True
                else:
                    # 3 秒之外了,并且没有被封,或者超出解禁时间范围的,
                    #  次数和时间都应该重新计算
                    print("来了兄弟", REJ_IP, int(time.time()))
                    __tmp_d = {'count': 1,
                               'rejected': None,
                               'access_time': int(time.time())}
                    REJ_IP[ip].update(__tmp_d)
                    print("改过了", REJ_IP)
    
    class RejectIpMiddleware:
        def __init__(self, get_response):
            self.get_response = get_response
    
        def __call__(self, request):
            remote_ip = request.META['REMOTE_ADDR']
            # print(f"接收到请求后 --> 我在这里呀{remote_ip}--》调用视图前")
            if reject_ip(remote_ip):
                 return HttpResponse(f"访问受限")
            response = self.get_response(request)
            # print("调用视图后--》我在这里呀--》返回页面前")
            return response
    
    #在settings.py中
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'MyMiddieware.rejectip.RejectIpMiddleware',        #确定中间件的添加位置
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    

    详细过程

    http请求响应顺序.png
    1.用户通过浏览器请求一个页面
    2.请求到达Request Middlewares,中间件对request做一些预处理或者直接response请求
    3.URLConf通过urls.py文件和请求的URL找到相应的View
    4.View Middlewares被访问,它同样可以对request做一些处理或者直接返回response
    5.调用View中的函数
    6.View中的方法可以选择性的通过Models访问底层的数据
    7.所有的Model-to-DB的交互都是通过manager完成的
    8.如果需要,Views可以使用一个特殊的Context
    9.Context被传给Template用来生成页面
    a.Template使用Filters和Tags去渲染输出
    b.输出被返回到View
    c.HTTPResponse被发送到Response Middlewares
    d.任何Response Middlewares都可以丰富response或者返回一个完全不同的response
    e.Response返回到浏览器,呈现给用户
    

    相关文章

      网友评论

          本文标题:自定义验证类,ajax,中间件

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