Django 权限系统项目实战详细图文教程 2--环境搭建

来源引用网络知识与某站曹老师视频相互结合学习记录,仅供参考!

架构搭建

三、引入 JWT 前后端交互

Json Web Token (JWT) 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准(RFC 7519);JWT就是一段字符串,主要是用来进行用户身份认证的凭证,如前后端不分离,用户会话时会临时生成一个 Session 存在服务端,再结合前端 Cookie;现在前后端分离的话, 也需要一个标识,就引用的 Json web token (JWT),它的组成字符串由"头部(Header)、载荷(Payload)和签名(Signature)"三部分组成;

复制代码
​ 头部(Header):
JWT的头部通常由两部分组成:令牌的类型(即JWT)和使用的签名算法;
例如:一个简单的头部可以是: { "alg": "HS256", "typ": "JWT" } 
该头部的意思是使用HS256算法进行签名,并且类型是JWT;

​ 载荷(Payload): 
载荷是JWT的第二个部分,也被称为声明(Claims);它包含了一些被称为声明的实体;
(例如用户、用户角色等)的信息。载荷可以包含一组标准声明,
例如: { "sub": "1234567890", "name": "John Doe", "iat": 1516239022 } 
还可以包含自定义的声明,例如: { "role": "admin" };

​ 签名(Signature): 
要创建JWT的签名部分,需要使用头部和载荷以及密钥进行签名;
签名用于验证消息的完整性和验证发件人的身份;
例如:用于创建签名的算法可以是HMAC SHA256(使用字符串和密钥并加密生成签名),或者是RSA或ECDSA(使用公钥加密和私钥解密)等;服务端需要保存加密用的密钥,以便后续的签名验证;

总结起来,JWT由三部分组成:头部(Header)、载荷(Payload )和签名(Signature);头部用于描述签名的算法和类型,载荷用于存储信息的声明,签名用于验证消息的完整性和验证发件人的身份。

具体流程如下(烦请自行参考):

  1. 前端用户认证发起"提交用户名、密码",后端进行认证;
  2. 认证通过之后会通过 JWT 生成 Token,就是会话标识返回给前端,前端会进行浏览器保存;
  3. 其他后端请求在 headers 请求头中携带 Token,然后后端拦截器进行拦截、判断 Token;
    • 如果是认证成功的,没有过期且是正确的话,就执行业务逻辑,返回数据,前端进行展示;
    • 如果 Token 失效了或者 Token 不存在或者错误,则返回错误信息给前端进行下一步处理;

这是一种非常好的设计,前后端分离开发均是这么做的;
在实际开发过程中是基于 DRF 框架使用 JWT(推荐),DRF(Django Rest Framework)是用于构建 API 的成熟且广泛使用的 Python 库;它是基于流行的 Python Web 框架 Django 构建的一个轻量级 REST 框架,主要是为了方便 Web 开发而引入的,旨在简化复杂的数据访问API的开发过程;如果已经熟悉 Django 框架,那么学习 DRF 将会非常直接,因为它使用了很多 Django 中已有的概念,并添加了额外的功能来支持 RESTful API 的设计;

DRF(Django Rest Framework)官方网站(烦请自行探索):https://www.django-rest-framework.org/

JWT 基于 DRF 的一个扩展(自行探索了解,只有几个接口):https://github.com/jpadilla/django-rest-framework-jwt

DRF(Django Rest Framework)主要特点:

  • 简单易用:DRF提供了许多开箱即用的功能;例如:认证策略、内容协商、限流等,使得开发者能够快速地搭建出 RESTful 风格的服务端接口;
  • 自动化的URL路由:它允许定义清晰的 URL 模式,并自动生成相应的视图,从而减少了编写常规代码的时间;
  • 序列化支持:DRF内建了序列化功能,可以帮忙将模型实例转换为JSON或其他格式的数据,以及反序列化请求数据到模型对象;比较实用,自己整序列化比较麻烦;
  • 灵活的配置:虽然提供了很多默认设置,但是 DRF 也非常容易根据项目需求进行定制;
  • 丰富的文档支持:可以自动生成 API 文档,帮助前端开发者或第三方更好地理解和使用 API;
安装第三方库

drf 和 drf-jwt 安装、使用 PyCharm 工具 Python 解释器安装或者命令安装,自行选择;

复制代码
# drf安装
pip install djangorestframework -i https://pypi.tuna.tsinghua.edu.cn/simple
# drf-jwt 安装
pip install djangorestframework-jwt -i https://pypi.tuna.tsinghua.edu.cn/simple

1、安装完成之后去配置文件中设置添加,修改项目"python_admin"应用下的"settings.py"配置文件,在"INSTALLED_APPS"配置项中添加相对应的"rest_framework"和"rest_framework_jwt";设置完成后就可以在实际项目里面使用到了;

复制代码
"""
Django settings for python_admin project.

Generated by 'django-admin startproject' using Django 6.0.7.

For more information on this file, see
https://docs.djangoproject.com/en/6.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/6.0/ref/settings/
"""

from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-imdr37+f#1u-6spy0ch)49cr1=gkg8gr#x3dzx@)&f0)1qg_=!'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'rest_framework_jwt',
    "user.apps.UserConfig",
    "role.apps.RoleConfig",
    "menu.apps.MenuConfig"
]

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',
]

ROOT_URLCONF = 'python_admin.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates']
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'python_admin.wsgi.application'


# Database
# https://docs.djangoproject.com/en/6.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'db_admin',
        'USER': 'root',
        'PASSWORD': '123',
        'HOST': '192.168.88.145',
        'PORT': '3306'
    }
}


# Password validation
# https://docs.djangoproject.com/en/6.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/6.0/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/6.0/howto/static-files/

STATIC_URL = 'static/'

2、修改项目"user"子模块应用下的"views.py"文件内容,新增定义一个 JwtTestView 测试类,模拟登录的一个测试类,相当于是模拟登录认证成功,然后给用户前端返回一个 Token;

复制代码
from django.http import JsonResponse
from django.shortcuts import render
from django.views import View
from rest_framework_jwt.settings import api_settings

from user.models import SysUser


# Create your views here.

# 定义TestView类(导包引入from django.views import View)
class TestView(View):

    def get(self, request):
        # 导包引入from user.models import SysUser,通过objects.all()查询所有用户信息
        userList_obj = SysUser.objects.all()
        print(f'打印查看userList_obj类型:{type(userList_obj)},查看: {userList_obj},')
        # 转存字典,里面的对象转换为了字典类型
        userList_dict = userList_obj.values()
        print(f'打印查看userList_dict2类型: {type(userList_dict)},查看:{userList_dict}')
        # 把外层的容器转为List
        userList = list(userList_dict)
        print(f'打印查看userList类型: {type(userList)},查看:{userList}')
        # 导包引入from django.http import JsonResponse
        return JsonResponse({'code': 200, 'info': '测试', 'data': userList})

# 定义一个 JwtTestView 测试类,模拟登录
class JwtTestView(View):

    # get请求方式
    def get(self, request):
        # 这里模拟登录是直接从之前添加测试数据的表中获取,返回的是一个用户user
        user = SysUser.objects.get(username='jack', password='123456')
        # 导包引入from rest_framework_jwt.settings import api_settings模块
        # 获取 JWT_PAYLOAD_HANDLER 荷载方法,其实就是内容,返回的是一个函数对象
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        # 编码处理 JWT_ENCODE_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
        # 上面两个方法获取到之后就可以进行操作了,第一步:将用户对象传递进去,获取到该对象的属性值
        payload = jwt_payload_handler(user)
        # 将属性编码成jwt格式的字符串,其实就是生成token
        token = jwt_encode_handler(payload)
        return JsonResponse({'code': 200, 'token': token})

3、修改项目"user"子模块应用下的"urls.py"文件内容,配置映射关系;

复制代码
from django.urls import path
from user.views import TestView, JwtTestView

urlpatterns = [
    path('test', TestView.as_view(), name='test'),  # test测试
    path('jwt_test', JwtTestView.as_view(), name='jwt_test'),  # JWT测试
]

4、运行启动项目,浏览器输入"http://127.0.0.1:8000/user/jwt_test"测试验证,能够生成对应的 token 串且每次生成的都是不一样;建议这里可以保存一个 token 值,方便下面接口测试,若未保存,到时候使用时再生成一个即可;

5、修改项目"user"子模块应用下的"views.py"文件内容,更改查询用户信息的 TestView 测试类,要求有 token 才能够访问到;

复制代码
from django.http import JsonResponse
from django.shortcuts import render
from django.views import View
from rest_framework_jwt.settings import api_settings

from user.models import SysUser


# Create your views here.

# 定义TestView类(导包引入from django.views import View)
class TestView(View):

    def get(self, request):
        # 获取token,需注意在前端是叫"AUTHORIZATION"这个名字,而到Django中则会自动添加"HTTP_"变为"HTTP_AUTHORIZATION"
        token = request.META.get('HTTP_AUTHORIZATION')
        print(f'打印查看token值: {token}')
        # 判断token不等于None值且不为空值,就表示通过了
        if token != None and token != '':
            # 导包引入from user.models import SysUser,通过objects.all()查询所有用户信息
            userList_obj = SysUser.objects.all()
            print(f'打印查看userList_obj类型:{type(userList_obj)},查看: {userList_obj},')
            # 转存字典,里面的对象转换为了字典类型
            userList_dict = userList_obj.values()
            print(f'打印查看userList_dict2类型: {type(userList_dict)},查看:{userList_dict}')
            # 把外层的容器转为List
            userList = list(userList_dict)
            print(f'打印查看userList类型: {type(userList)},查看:{userList}')
            # 导包引入from django.http import JsonResponse
            return JsonResponse({'code': 200, 'info': '测试', 'data': userList})
        else:
            # 否则的话就给前端返回401
            return JsonResponse({'code': 401, 'info': '没有测试访问权限!'})

# 定义一个 JwtTestView 测试类,模拟登录
class JwtTestView(View):

    # get请求方式
    def get(self, request):
        # 这里模拟登录是直接从之前添加测试数据的表中获取,返回的是一个用户user
        user = SysUser.objects.get(username='jack', password='123456')
        # 导包引入from rest_framework_jwt.settings import api_settings模块
        # 获取 JWT_PAYLOAD_HANDLER 荷载方法,其实就是内容,返回的是一个函数对象
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        # 编码处理 JWT_ENCODE_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
        # 上面两个方法获取到之后就可以进行操作了,第一步:将用户对象传递进去,获取到该对象的属性值
        payload = jwt_payload_handler(user)
        # 将属性编码成jwt格式的字符串,其实就是生成token
        token = jwt_encode_handler(payload)
        return JsonResponse({'code': 200, 'token': token})

6、浏览器输入"http://127.0.0.1:8000/user/test"直接访问,会提示没有访问权限,因为现在需要带有 token 才可以访问到;

7、使用接口测试工具,烦请自行选择,例如:Postman、Apifox 等等,分别测试验证"http://127.0.0.1:8000/user/test"接口在不携带请求头参数"AUTHORIZATION(这里不需要加'HTTP',因为后端默认会添加)"和携带请求头参数的返回结果;

8、打开前端 vue 项目"python_vue5_admin",在"src"目录下新建一个名称为"util"的目录文件,在"util"目录文件路径下新建一个名称为"request.js"的 JS 文件,输入以下内容;大致就是封装了的请求工具类,通过axios请求后端接口;

复制代码
// 引入axios
import axios from 'axios';


let baseUrl="http://localhost:8000/";
// 创建axios实例
const httpService = axios.create({
    // url前缀-'http:xxx.xxx'
    // baseURL: process.env.BASE_API, // 需自定义
    baseURL:baseUrl,
    // 请求超时时间
    timeout: 3000 // 需自定义
});

//添加请求和响应拦截器
// 添加请求拦截器
httpService.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    config.headers.AUTHORIZATION=window.sessionStorage.getItem('token');
    return config;
}, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
});

// 添加响应拦截器
httpService.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    return response;
}, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
});

/*网络请求部分*/

/*
 *  get请求
 *  url:请求地址
 *  params:参数
 * */
export function get(url, params = {}) {
    return new Promise((resolve, reject) => {
        httpService({
            url: url,
            method: 'get',
            params: params
        }).then(response => {
            resolve(response);
        }).catch(error => {
            reject(error);
        });
    });
}

/*
 *  post请求
 *  url:请求地址
 *  params:参数
 * */
export function post(url, params = {}) {
    return new Promise((resolve, reject) => {
        httpService({
            url: url,
            method: 'post',
            data: params
        }).then(response => {
            console.log(response)
            resolve(response);
        }).catch(error => {
            console.log(error)
            reject(error);
        });
    });
}

/*
 *  delete请求
 *  url:请求地址
 *  params:参数
 * */
export function del(url, params = {}) {
    return new Promise((resolve, reject) => {
        httpService({
            url: url,
            method: 'delete',
            data: params
        }).then(response => {
            console.log(response)
            resolve(response);
        }).catch(error => {
            console.log(error)
            reject(error);
        });
    });
}


/*
 *  文件上传
 *  url:请求地址
 *  params:参数
 * */
export function fileUpload(url, params = {}) {
    return new Promise((resolve, reject) => {
        httpService({
            url: url,
            method: 'post',
            data: params,
            headers: { 'Content-Type': 'multipart/form-data' }
        }).then(response => {
            resolve(response);
        }).catch(error => {
            reject(error);
        });
    });
}

export function getServerUrl(){
    return baseUrl;
}

export default {
    get,
    post,
    del,
    fileUpload,
    getServerUrl
}

9、继续修改"src"目录"views"目录文件下的"HomeView.vue"文件内容,写一个模拟登录的获取token的请求,再写一个业务接口请求;

复制代码
<template>

    <el-button type="primary" @click="handleLogin">测试登录</el-button>
    <el-button type="success" @click="handleUserList">测试获取用户信息列表</el-button>

</template>

<script setup>
import requestUtil from '@/util/request'

const handleLogin=async()=>{
  let result=await requestUtil.get("user/jwt_test")
  let data=result.data;
  if(data.code==200){
    const token=data.token
    console.log("登录成功,token="+token)
    window.sessionStorage.setItem("token",token)
  }else{
    console.log("登录出错")
  }
}

const handleUserList=async ()=>{
  let result=await requestUtil.get("user/test")
  let data=result.data;
  if(data.code==200){
    const userList=data.data;
    console.log("用户信息列表,userList="+userList)
  }else{
    console.log("登录出错")
  }
}

</script>

10、浏览器输入"http://127.0.0.1:8080/"测试验证,记得启动前端项目,在终端命令窗口输入"npm run serve"命令启动项目,启动成功后自行打开测试查看;点击任意按钮,可以看到后端报错信息端口号是"8000",而前端是"8080",它们不属于同一个域,为了安全着想,所以默认是不允许进行跨域访问的;

四、跨域问题解决

CORS(跨域资源共享,Cross-Origin Resource Sharing)是一种跨域访问的机制,可让Ajax实现跨域访问;在服务器端可以设置允许,在服务器的response header中,加入"Access-Control-Allow-Origin: *"便可支持CORS;但是一个个添加会非常麻烦,所以有人开发了一个库叫"CORS-header"可以直接支持,只需在settings.py中做一些简单的配置即可,其他不用作任何修改,也不用自己手动的创建中间件对response处理了,直接用以下配置即可, 现在用起来服务器端完全开放,开启CORS,没有任何跨域烦恼;

安装第三方库 django-cors-headers

11、安装django-cors-headers库,烦请自行安装;

复制代码
# 安装django-cors-headers库命令
pip install django-cors-headers -i https://pypi.tuna.tsinghua.edu.cn/simple
配置添加到应用程序中

12、修改项目"python_admin"应用下的"settings.py"配置文件,在"INSTALLED_APPS"配置项中添加相对应的"corsheaders",可自行放置,无顺序要求;

复制代码
INSTALLED_APPS = [
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'rest_framework_jwt',
    'corsheaders',
    "user.apps.UserConfig",
    "role.apps.RoleConfig",
    "menu.apps.MenuConfig"
]

13、修改项目"python_admin"应用下的"settings.py"配置文件,在"MIDDLEWARE"配置项中添加相对应的"corsheaders.middleware.CorsMiddleware"设置项,注意需要必须放在"django.middleware.common.CommonMiddleware"设置项之前,建议可以直接把"corsheaders.middleware.CorsMiddleware"设置项直接放在第一位,不然可能会造成某些请求没有添加CORS;

复制代码
MIDDLEWARE = [
    'django.middleware.common.CommonMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
设置访问白名单

14、修改项目"python_admin"应用下的"settings.py"配置文件内容,添加"CORS_ORIGIN_ALLOW_ALL = True"设置项;

复制代码
# CORS_ORIGIN_ALLOW_ALL为True, 指定所有域名(ip)都可以访问后端接口, 默认为False
CORS_ORIGIN_ALLOW_ALL = True
设置允许携带cookie

15、修改项目"python_admin"应用下的"settings.py"配置文件内容,添加"CORS_ALLOW_CREDENTIALS = True"设置项,一般情况下都需要设置此项;

复制代码
CORS_ALLOW_CREDENTIALS = True
设置默认允许请求头方法

16、修改项目"python_admin"应用下的"settings.py"配置文件内容,添加"CORS_ALLOW_METHODS"设置项,默认请求方法,建议可以把所有的请求方法都写上就可以了;

复制代码
"""
Django settings for python_admin project.

Generated by 'django-admin startproject' using Django 6.0.7.

For more information on this file, see
https://docs.djangoproject.com/en/6.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/6.0/ref/settings/
"""

from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-imdr37+f#1u-6spy0ch)49cr1=gkg8gr#x3dzx@)&f0)1qg_=!'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'rest_framework_jwt',
    'corsheaders',
    "user.apps.UserConfig",
    "role.apps.RoleConfig",
    "menu.apps.MenuConfig"
]

MIDDLEWARE = [
    'django.middleware.common.CommonMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

CORS_ORIGIN_ALLOW_ALL = True

CORS_ALLOW_CREDENTIALS = True

CORS_ALLOW_METHODS = [
    'GET',
    'POST',
    'PUT',
    'PATCH',
    'DELETE',
]

ROOT_URLCONF = 'python_admin.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates']
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'python_admin.wsgi.application'


# Database
# https://docs.djangoproject.com/en/6.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'db_admin',
        'USER': 'root',
        'PASSWORD': '123',
        'HOST': '192.168.88.145',
        'PORT': '3306'
    }
}


# Password validation
# https://docs.djangoproject.com/en/6.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/6.0/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/6.0/howto/static-files/

STATIC_URL = 'static/'

17、以上的配置信息都设置完成之后就可以在实际项目里面使用了,浏览器输入"http://127.0.0.1:8080/"测试验证,点击任意按钮,可以看到已经能够请求到数据信息了,能够说明跨域请求访问配置已经成功设置完成。

未完待续......

相关推荐
高频因子挖掘机2 小时前
QuantDash 明明安装成功,为什么 Python 还是无法 import?
后端·github·api
4SAPI7 小时前
多模型请求路由怎么设计?成本、速度和能力如何平衡
人工智能·python·gateway·php
Java爱好狂.9 小时前
Java初学者如何一周速通SpringBoot!
java·spring boot·后端·spring·高并发·架构师·java面试
XCDoris9 小时前
郴州logo设计机构
大数据·人工智能·python
gCode Teacher 格码致知10 小时前
Pandas教学-17:Series与Dataframe的关系
开发语言·python·pandas
马良神笔11 小时前
2026 年Rag最近技术前沿总结
后端·python·django
程序猿DD11 小时前
同样10美元,OpenDesign和Command Code的DeepSeek V4.1 Flash额度到底有多少?
后端
不像程序员的程序媛11 小时前
maven基础
python·pycharm·maven
高频因子挖掘机11 小时前
A股量化从日线升级到5分钟线:数据量增加后最先暴露哪些工程问题?
后端·github·api