【Python】Django知识点记录

最近在做django 项目,重温动态语言的魅力

Django cors跨域解决

from django.utils.deprecation import MiddlewareMixin
class CorsMiddleware(MiddlewareMixin):
    def process_response(self, request, response):
        response['Access-Control-Allow-Origin'] = "*"
        response['Access-Control-Allow-Headers'] = "*"
        response['Access-Control-Allow-Credentials'] = "true"
        response['Access-Control-Allow-Methods'] = "POST, OPTIONS, GET, PUT"
        return response
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',
    'corsheaders.middleware.CorsMiddleware',
    'AIService.cors_middleware.CorsMiddleware'
]

理解WSGI 接口

根据Python的惯例,Django不是一个完整的Web后端框架,它只负责开发WSGI应用程序 ,在生产环境中Django应用应当与一个WSGI服务器配套,由WSGI服务器负责网络通讯部分。

WSGI,全称 Web Server Gateway Interface,或者 Python Web Server Gateway
Interface ,是为 Python语言定义的Web服务器和Web应用程序之间的一种简单而通用的接口。Gateway,也就是网关。网关的作用就是在协议之间进行转换。

它主要负责http协议的解析和组装,web服务器把解析好的所有数据发送给web应用(django),web应用决定返回哪个html页面发送给web服务器,web服务器组装好后在发送给客户端.
在这里插入图片描述

uWSGI Web服务器, 它与WSGI协议的关系

uWSGI是一个Web服务器,它实现了WSGI协议、uwsgi、http等协议。Nginx中HttpUwsgiModule的作用是与uWSGI服务器进行交换。

wsgi server (比如uWSGI) 要和 wsgi application(比如django )交互,uwsgi需要将过来的请求转给django 处理,那么uWSGI 和 django的交互和调用就需要一个统一的规范,这个规范就是WSGI WSGI(Web Server Gateway Interface)

uwsgi协议

uwsgi是服务器和服务端应用程序的通信协议,规定了怎么把请求转发给应用程序和返回

如何区分项目配置(生产、测试)

本地调试: 终端指定 settings

python3 manage.py runserver --settings=AIService.debug_settings

部署: Dockerfile中指定不同的wsgi.py文件来区分

CMD ["gunicorn", "-c", "gunicorn.conf.py", "AIService.debug_wsgi"]
CMD ["gunicorn", "-c", "gunicorn.conf.py", "AIService.wsgi"]

如何在Django中启动一个辅助线程工作?

answer: Try to call your init code from end of wsgi.py file. It will be executed once at start of server.

example: 启动一个mq消费线程工作

import django
from django.core.handlers.wsgi import WSGIHandler


def get_wsgi_application():
    """
    The public interface to Django's WSGI support. Return a WSGI callable.

    Avoids making django.core.handlers.WSGIHandler a public API, in case the
    internal WSGI implementation changes or moves in the future.
    """
    django.setup(set_prefix=False)
    # 把主进程中的kafka consumer线程放入启动过程中(即放入gunicorn的master进程中),
    # 以使用gunicorn的preload参数控制这些线程的启动个数。
    from utils.mq import consumer, start_consumer_daemon
    start_consumer_daemon()
    return WSGIHandler()


开一个线程

def start_consumer_daemon():
    try:
        for _ in range(1):
            t = threading.Thread(target=consumer)
            t.setDaemon(True)
            t.start()
    except Exception as e:
        logger.error(e)

https://stackoverflow.com/questions/14630467/starting-a-simple-python-thread-on-django-init

Django中实现自定义中间件?

from django.utils.deprecation import MiddlewareMixin
from utils.key import gen_appraiser_token_key
from django.http.response import HttpResponse
from utils.redis import r
from .models import *

RequestMetaUserKey = "HTTP_USERID"


class AppraiserAuth(MiddlewareMixin):
    def process_request(self, request):
        token = request.META.get("HTTP_AUTHORIZATION")
        if token is None:
            return HttpResponse('Unauthorized', status=401)
        key = gen_appraiser_token_key(token)
        id = r.connection.get(key)
        if not id:
            return HttpResponse('errmsg', status=401)
        appraiser = Appraiser.objects.filter(pk=int(id), status="1").first()
        if not appraiser:
            return HttpResponse('errmsg', status=401)
        request.META[RequestMetaUserKey] = appraiser.id

    def process_response(self, request, response):
        return response

from django.utils.decorators import decorator_from_middleware

@api_view(["POST"])
@decorator_from_middleware(AppraiserAuth)
def appraiser_detail(request):
    """h5请求"""
    pb_req = h5_manual_appraisal_pb.TSManualAppraiserDetailRequest()
    pb_res = h5_manual_appraisal_pb.TSManualAppraiserDetailResponse()
    # 校验请求参数
    try:
        req_data = pb_to_dict(request.body, pb_req)
    except Exception as e:
        logger.warning(f"pb to dict failed:{e}")
        res_data = {
            "errorCode": 10022,
            "errorMsg": "Invalid params",
        }
        return HttpResponse(dict_to_pb(res_data, pb_res), content_type=PB_CONTENT_TYPE)

    moaid = req_data.get("moaid")
    invalid_params = []
    if not moaid:
        invalid_params.append("moaid")
    if invalid_params:
        res_data = {
            "errorCode": 10022,
            "errorMsg": f"Invalid params: {invalid_params}",
        }
        return HttpResponse(dict_to_pb(res_data, pb_res), content_type=PB_CONTENT_TYPE)

    appraiser_id = request.META.get(RequestMetaUserKey)

proto与dict互转

from google.protobuf.json_format import MessageToDict, ParseDict

PB_CONTENT_TYPE = "application/x-protobuf"


def pb_to_dict(pb_str, pb):
    pb.ParseFromString(pb_str)
    return MessageToDict(pb, preserving_proto_field_name=True)


def dict_to_pb(pb_dict, pb):
    ParseDict(pb_dict, pb)
    return pb.SerializeToString()

    res_data = {
        "errorCode": 0,
        "errorMsg": "Success",
    }

    try:
        pb_res_data = dict_to_pb(res_data, pb_res)
    except Exception as e:
        logger.warning(f"dict to pb failed:{e}\n dict:{res_data}")
        res_data = {
            "errorCode": 10026,
            "errorMsg": "Serialize response to protobuf failed",
        }
        return HttpResponse(dict_to_pb(res_data, pb_res), content_type=PB_CONTENT_TYPE)

    return HttpResponse(pb_res_data, content_type=PB_CONTENT_TYPE)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值