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

2019-09-25  本文已影响0人  快去学习不然怎么去看aimer

自定义验证类

在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返回到浏览器,呈现给用户
上一篇下一篇

猜你喜欢

热点阅读