三角网站建设,合肥网站建设案例,上海seo推广整站,计算机培训机构推荐项目介绍
一直想做一款大学社团管理系统#xff0c;看了很多优秀的开源项目但是发现没有合适的。于是利用空闲休息时间开始自己写了一套管理系统。
在线体验
代码下载#xff1a;https://github.com/geeeeeeeek/python_team演示地址#xff1a;http://team.gitapp.cn/
看了很多优秀的开源项目但是发现没有合适的。于是利用空闲休息时间开始自己写了一套管理系统。
在线体验
代码下载https://github.com/geeeeeeeek/python_team演示地址http://team.gitapp.cn/
账号admin123 密码admin123
功能介绍
系统分为后台和前台两部分。
后台的主要功能
社团管理管理系统可以录入、修改和查询社团的基本信息如社团名称、地址、备注等。类型管理系统可以管理社团的类型信息包括类型的名称等。标签管理管理标签录入、修改和查询标签的信息。评论管理管理和浏览整个网站的评论信息。成员管理管理和浏览社团的成员信息。用户管理管理和浏览网站的用户信息可以新增、编辑和删除用户。统计分析系统可以根据社团的活动数据和会员参与度进行统计和分析帮助管理员了解整个系统的状况。消息管理社团管理员可以在系统上发布消息整个网站的用户都能收到。系统信息管理员可以查看系统的基本信息包括系统名称、服务器信息、内存信息、cpu信息、软件信息等。
前台的主要功能
注册登录用户通过注册和登录后才能使用网站。门户浏览用户进入首页后可以浏览社团列表信息包括最新、最热、推荐。智能推荐详情页右侧的热门推荐。用户中心包括用户基本资料修改、用户邮箱推送、消息。我的加入包括我申请的社团的信息。模糊搜索顶部搜索功能支持模糊搜索社团信息。社团评论详情页下侧用户可以评论社团。
开发环境
后端 Python 3.8 Django 3.2前端 Javascript Vue数据库MySQL 5.7开发平台Pycharm vscode运行环境Windows 10/11
关键技术
前端技术栈 ES6、vue、vuex、vue-router、vue-cli、axios、antd后端技术栈 Python、Django、pip
后端技术
django框架
Django是一款基于Python开发的全栈式一体化Web应用框架。2003年问世之初它只是美国一家报社的内部工具2005年7月使用BSD许可证完成了开源。Django采用MTV设计模式即Model模型 Template模板 View视图。它遵循MVC设计并且内置了对象关系映射ORM层使得开发者无需关心底层的数据存取细节可以更专注于业务逻辑的开发。
Django的目的是削减代码量简单且迅速地搭建以数据库为主体的复杂Web站点。它是全栈式框架因此安装起来很简单而且使用者众多。这使得Django除具有完备的官方文档之外还有大量的关联文档、丰富的第三方库可供使用。与其他框架相比Django用起来要轻松得多。
优点
提供了定义序列化器Serializer的方法。可以快速根据Django ORM或者其他库自动序列化或反序列化。提供了丰富的类视图MIXIN扩展类。可以简化视图的编写。具有丰富的定制层级。包括函数视图、类视图还可以将视图与自动生成API结合满足各种需求。支持多种身份认证和权限认证方式。内置了限流系统。
前端技术
npmnode.js的包管理工具用于统一管理我们前端项目中需要用到的包、插件、工具、命令等便于开发和维护。ES6Javascript的新版本ECMAScript6的简称。利用ES6我们可以简化我们的JS代码同时利用其提供的强大功能来快速实现JS逻辑。vue-cliVue的脚手架工具用于自动生成Vue项目的目录及文件。vue-router Vue提供的前端路由工具利用其我们实现页面的路由控制局部刷新及按需加载构建单页应用实现前后端分离。vuexVue提供的状态管理工具用于统一管理我们项目中各种数据的交互和重用存储我们需要用到数据对象。Ant-design基于MVVM框架Vue开源出来的一套前端ui组件。
运行步骤
后端运行步骤
(1) 安装mysql数据库启动服务
(2) 打开cmd命令行进入mysql并新建数据库
mysql -u root -p
CREATE DATABASE IF NOT EXISTS python_team DEFAULT CHARSET utf8 COLLATE utf8_general_ci;(3) 恢复sql数据
use xxx
source xxxx.sql(4) 修改settings.py中的配置信息
(5) 安装python 3.8
(6) 安装依赖包
pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple(7) 运行命令
python manage.py runserver 前端运行步骤
(1) 安装node 16
(2) cmd进入web目录下安装依赖执行:
npm install (3) 运行项目
npm run dev代码结构
后端结构
server
├── myapp // 主应用
│ └── auth // 认证管理
│ └── middlewares // 中间件
│ └── permission // 权限
│ └── views // 视图与接口主要业务代码
│ └── models.py // 状态码
│ └── serializers.py // 状态码
│ └── urls.py // 状态码
│ └── utils.py // 状态码
├── entity // 实体类
├── interceptor // 拦截器
├── mapper // 数据库映射
├── server // 配置目录
├── upload // 静态资源目录
├── requiements.txt // 依赖项前端结构
├── build // 构建相关
├── public // 公共文件
│ ├── favicon.ico // favicon图标
│ └── index.html // html模板
├── src // 源代码
│ ├── api // 所有请求
│ ├── assets // 主题 字体等静态资源
│ ├── router // 路由
│ ├── store // 全局 store管理
│ ├── utils // 全局公用方法
│ ├── views // view界面
│ ├── App.vue // 入口页面
│ ├── main.js // 入口 加载组件 初始化等
│ └── settings.js // 系统配置
├── .eslintignore // 忽略语法检查
├── .eslintrc.js // eslint 配置项
├── .gitignore // git 忽略项
├── babel.config.js // babel.config.js
├── package.json // package.json
└── vite.config.js // vue配置数据库设计
需求分析
在社团管理系统中需要存储和管理社团信息、评论信息、分类信息、标签信息、用户信息、通知信息、日志信息。
实体设计如下
社团(thing)分类(classification)标签(tag)用户(user)评价(comment)日志(log)通知(notice)
关系如下
一个社团有一个分类一个分类可以对应多个社团一个社团有多个标签一个标签可以对应多个社团
数据表设计如下 // 社团
Table thing {thing_id int [pk]classification_id int [ref: C.classification_id]tag_id int [ref: tag.tag_id]title varcharcover varchar // 封面zongzhi varchar // 社团宗旨price varchar // 价格status int // 上线0 下架1description textmobile varchar email varchar // 邮箱location varchar // 社团地址create_time datetimepv intwish_count intrecommend_count intwish int [ref: user.user_id]collect int [ref: user.user_id]}// 分类管理Table classification as C {classification_id int [pk]pid inttitle varcharcreate_time datetime}Table tag {tag_id int [pk]title varcharcreate_time datetime}// 评论Table comment {comment_id int [pk]content varcharuser_id int [ref: user.user_id]thing_id int [ref: thing.thing_id]comment_time datetimelike_count int}// 用户Table user {user_id int [pk]role varchar // 1管理员 2普通用户 3演示帐号status int // 0正常 1封号username varcharpassword varcharnickname varcharavatar varchardescription varcharwish int [ref: thing.thing_id]email varcharmobile varcharscore int // 积分push_email varchar // 推送邮箱push_switch int // 推送开关token varcharadmin_token varchar} Table record {record_id int [pk]user_id int [ref: user.user_id]classification_id int [ref: C.classification_id]thing_id int [ref: thing.thing_id]title varcharrecord_time varchar}Table login_log {log_id int [pk]username varcharip varcharlog_time datetime}// 操作日志Table op_log {id int [pk]re_ip varcharre_time datetimere_url varcharre_method varcharre_content varcharaccess_time varchar}// 异常日志Table error_log {id int [pk]ip varcharmethod varcharcontent varcharlog_time varchar}// 成员管理Table order {order_id int [pk]user_id int [ref: user.user_id]thing_id int [ref: thing.thing_id]status varchar // 1未审核 2通过 7取消加入create_time datetime // 申请时间receiver_name varchar // 姓名receiver_address varchar // 地址receiver_phone varchar // 电话remark varchar // 备注}// 通知Table notice {id int [pk]content varcharcreate_time datetime}
开发过程
无论是社团管理、用户管理、标签管理、分类管理、评价管理、日志管理、消息管理等功能都是基于springbootvue框架开发的开发流程是
第一步编写实体第二步编写序列化层第三步编写views层第四步编写界面和API
下面用社团管理功能来演绎这个流程其它的管理功能都是这个流程。
第一步编写实体类
在server下的myapp下的models.py下面新建Thing类。并写入如下代码
class Thing(models.Model):STATUS_CHOICES ((0, 上架),(1, 下架),)id models.BigAutoField(primary_keyTrue)classification models.ForeignKey(Classification, on_deletemodels.CASCADE, blankTrue, nullTrue,related_nameclassification_thing)tag models.ManyToManyField(Tag, blankTrue)title models.CharField(max_length100, blankTrue, nullTrue)cover models.ImageField(upload_tocover/, nullTrue)description models.TextField(max_length1000, blankTrue, nullTrue)price models.CharField(max_length50, blankTrue, nullTrue) mobile models.CharField(max_length50, blankTrue, nullTrue)age models.CharField(max_length10, blankTrue, nullTrue) location models.CharField(max_length50, blankTrue, nullTrue) status models.CharField(max_length1, choicesSTATUS_CHOICES, default0)create_time models.DateTimeField(auto_now_addTrue, nullTrue)pv models.IntegerField(default0)recommend_count models.IntegerField(default0)wish models.ManyToManyField(User, blankTrue, related_namewish_things)wish_count models.IntegerField(default0)collect models.ManyToManyField(User, blankTrue, related_namecollect_things)collect_count models.IntegerField(default0)class Meta:db_table b_thing第二步编写序列化层
在server下的myapp下的serializers.py下新建ThingSerializer类并写入代码
class ThingSerializer(serializers.ModelSerializer):# 额外字段classification_title serializers.ReadOnlyField(sourceclassification.title)class Meta:model Thingfields __all__
第三步编写views层
在server的myapp下的views下新建Thing.py代码并写入代码实现增删改查 # 查
api_view([GET])
def list_api(request):if request.method GET:keyword request.GET.get(keyword, None)c request.GET.get(c, None)tag request.GET.get(tag, None)if keyword:things Thing.objects.filter(title__containskeyword).order_by(create_time)elif c:classification Classification.objects.get(pkc)things classification.classification_thing.all()elif tag:tag Tag.objects.get(idtag)print(tag)things tag.thing_set.all()else:things Thing.objects.all().order_by(create_time)serializer ThingSerializer(things, manyTrue)return APIResponse(code0, msg查询成功, dataserializer.data)# 删
api_view([GET])
def detail(request):try:pk request.GET.get(id, -1)thing Thing.objects.get(pkpk)except Thing.DoesNotExist:utils.log_error(request, 对象不存在)return APIResponse(code1, msg对象不存在)if request.method GET:serializer ThingSerializer(thing)return APIResponse(code0, msg查询成功, dataserializer.data)# 增
api_view([POST])
authentication_classes([AdminTokenAuthtication])
def create(request):if isDemoAdminUser(request):return APIResponse(code1, msg演示帐号无法操作)serializer ThingSerializer(datarequest.data)if serializer.is_valid():serializer.save()return APIResponse(code0, msg创建成功, dataserializer.data)else:print(serializer.errors)utils.log_error(request, 参数错误)return APIResponse(code1, msg创建失败)# 改
api_view([POST])
authentication_classes([AdminTokenAuthtication])
def update(request):if isDemoAdminUser(request):return APIResponse(code1, msg演示帐号无法操作)try:pk request.GET.get(id, -1)thing Thing.objects.get(pkpk)except Thing.DoesNotExist:return APIResponse(code1, msg对象不存在)serializer UpdateThingSerializer(thing, datarequest.data)if serializer.is_valid():serializer.save()return APIResponse(code0, msg查询成功, dataserializer.data)else:print(serializer.errors)utils.log_error(request, 参数错误)return APIResponse(code1, msg更新失败)# 删
api_view([POST])
authentication_classes([AdminTokenAuthtication])
def delete(request):if isDemoAdminUser(request):return APIResponse(code1, msg演示帐号无法操作)try:ids request.GET.get(ids)ids_arr ids.split(,)Thing.objects.filter(id__inids_arr).delete()except Thing.DoesNotExist:return APIResponse(code1, msg对象不存在)return APIResponse(code0, msg删除成功)
然后将该接口添加到urls.py中即可。
第四步编写界面和API
打开前端web工程在views文件夹下新建thing.vue文件并编写代码
templatediv!--页面区域--div classpage-viewdiv classtable-operationsa-spacea-button typeprimary clickhandleAdd新增/a-buttona-button clickhandleBatchDelete批量删除/a-buttona-input-search addon-before名称 enter-button searchonSearch changeonSearchChange //a-space/diva-tablesizemiddlerowKeyid:loadingdata.loading:columnscolumns:data-sourcedata.dataList:scroll{ x: max-content }:row-selectionrowSelection:pagination{size: default,current: data.page,pageSize: data.pageSize,onChange: (current) (data.page current),showSizeChanger: false,showTotal: (total) 共${total}条数据,}template #bodyCell{ text, record, index, column }template v-ifcolumn.key operationspana clickhandleEdit(record)编辑/aa-divider typevertical /a-popconfirm title确定删除? ok-text是 cancel-text否 confirmconfirmDelete(record)a href#删除/a/a-popconfirm/span/template/template/a-table/div!--弹窗区域--diva-modal:visiblemodal.visile:forceRendertrue:titlemodal.titlewidth880pxok-text确认cancel-text取消cancelhandleCancelokhandleOkdiva-form refmyform :label-col{ style: { width: 80px } } :modelmodal.form :rulesmodal.rulesa-row :gutter24a-col span24a-form-item label社团名 nametitlea-input placeholder请输入 v-model:valuemodal.form.title //a-form-item/a-cola-col span12a-form-item label社团类型 nameclassificationa-selectplaceholder请选择allowClear:optionsmodal.cData:field-names{ label: title, value: id }v-model:valuemodal.form.classification//a-form-item/a-cola-col span12a-form-item label标签a-select modemultiple placeholder请选择 allowClear v-model:valuemodal.form.tagtemplate v-foritem in modal.tagDataa-select-option :valueitem.id{{ item.title }}/a-select-option/template/a-select/a-form-item/a-cola-col span24a-form-item label封面a-upload-draggernamefileacceptimage/*:multiplefalse:before-uploadbeforeUploadv-model:file-listfileListp classant-upload-drag-icontemplate v-ifmodal.form.coverUrlimg :srcmodal.form.coverUrl stylewidth: 60px; height: 80px //templatetemplate v-elsefile-image-outlined //template/pp classant-upload-text 请选择要上传的图片 /p/a-upload-dragger/a-form-item/a-cola-col span24a-form-item label社团简介a-textarea placeholder请输入 v-model:valuemodal.form.description //a-form-item/a-cola-col span12a-form-item label社团宗旨a-input placeholder请输入 v-model:valuemodal.form.zongzhi stylewidth: 100% //a-form-item/a-cola-col span12a-form-item label手机号a-input-number placeholder请输入 :min0 v-model:valuemodal.form.mobile stylewidth: 100% //a-form-item/a-cola-col span12a-form-item label社团邮箱a-input placeholder请输入 v-model:valuemodal.form.email stylewidth: 100% //a-form-item/a-cola-col span12a-form-item label社团地址a-input placeholder请输入 v-model:valuemodal.form.location stylewidth: 100% //a-form-item/a-cola-col span12a-form-item label状态 namestatusa-select placeholder请选择 allowClear v-model:valuemodal.form.statusa-select-option key0 value0在营/a-select-optiona-select-option key1 value1暂停/a-select-option/a-select/a-form-item/a-col/a-row/a-form/div/a-modal/div/div
/templatescript setup langtsimport { FormInstance, message, SelectProps } from ant-design-vue;import { createApi, listApi, updateApi, deleteApi } from //api/admin/thing;import { listApi as listClassificationApi } from //api/admin/classification;import { listApi as listTagApi } from //api/admin/tag;import { BASE_URL } from //store/constants;import { FileImageOutlined } from ant-design/icons-vue;const columns reactive([{title: 序号,dataIndex: index,key: index,width: 60,},{title: 名称,dataIndex: title,key: title,},{title: 社团宗旨,dataIndex: zongzhi,key: zongzhi,},{title: 社团邮箱,dataIndex: email,key: email,},{title: 手机号,dataIndex: mobile,key: mobile,},{title: 社团地址,dataIndex: location,key: location,},{title: 简介,dataIndex: description,key: description,customRender: ({ text, record, index, column }) (text ? text.substring(0, 10) ... : --),},{title: 状态,dataIndex: status,key: status,customRender: ({ text, record, index, column }) (text 0 ? 在营 : 暂停),},{title: 操作,dataIndex: action,key: operation,align: center,fixed: right,width: 140,},]);const beforeUpload (file: File) {// 改文件名const fileName new Date().getTime().toString() . file.type.substring(6);const copyFile new File([file], fileName);console.log(copyFile);modal.form.imageFile copyFile;return false;};// 文件列表const fileList refany[]([]);// 页面数据const data reactive({dataList: [],loading: false,keyword: ,selectedRowKeys: [] as any[],pageSize: 10,page: 1,});// 弹窗数据源const modal reactive({visile: false,editFlag: false,title: ,cData: [],tagData: [{}],form: {id: undefined,title: undefined,classification: undefined,tag: [],zongzhi: undefined,mobile: undefined,email: undefined,location: undefined,status: undefined,cover: undefined,coverUrl: undefined,imageFile: undefined,},rules: {title: [{ required: true, message: 请输入名称, trigger: change }],classification: [{ required: true, message: 请选择分类, trigger: change }],price: [{ required: true, message: 请输入定价, trigger: change }],status: [{ required: true, message: 请选择状态, trigger: change }],},});const myform refFormInstance();onMounted(() {getDataList();getCDataList();getTagDataList();});const getDataList () {data.loading true;listApi({keyword: data.keyword,}).then((res) {data.loading false;console.log(res);res.data.forEach((item: any, index: any) {item.index index 1;item.price item.price;});data.dataList res.data;}).catch((err) {data.loading false;console.log(err);});};const getCDataList () {listClassificationApi({}).then((res) {modal.cData res.data;});};const getTagDataList () {listTagApi({}).then((res) {res.data.forEach((item, index) {item.index index 1;});modal.tagData res.data;});};const onSearchChange (e: Event) {data.keyword e?.target?.value;console.log(data.keyword);};const onSearch () {getDataList();};const rowSelection ref({onChange: (selectedRowKeys: (string | number)[], selectedRows: DataItem[]) {console.log(selectedRowKeys: ${selectedRowKeys}, selectedRows: , selectedRows);data.selectedRowKeys selectedRowKeys;},});const handleAdd () {resetModal();modal.visile true;modal.editFlag false;modal.title 新增;// 重置for (const key in modal.form) {modal.form[key] undefined;}modal.form.cover undefined;};const handleEdit (record: any) {resetModal();modal.visile true;modal.editFlag true;modal.title 编辑;// 重置for (const key in modal.form) {modal.form[key] undefined;}for (const key in record) {if (record[key]) {modal.form[key] record[key];}}if (modal.form.cover) {modal.form.coverUrl BASE_URL modal.form.cover;modal.form.cover undefined;}};const confirmDelete (record: any) {console.log(delete, record);deleteApi({ ids: record.id }).then((res) {getDataList();}).catch((err) {message.error(err.msg || 操作失败);});};const handleBatchDelete () {console.log(data.selectedRowKeys);if (data.selectedRowKeys.length 0) {console.log(hello);message.warn(请勾选删除项);return;}deleteApi({ ids: data.selectedRowKeys.join(,) }).then((res) {message.success(删除成功);data.selectedRowKeys [];getDataList();}).catch((err) {message.error(err.msg || 操作失败);});};const handleOk () {myform.value?.validate().then(() {const formData new FormData();if (modal.editFlag) {formData.append(id, modal.form.id);}formData.append(title, modal.form.title);if (modal.form.classification) {formData.append(classification, modal.form.classification);}if (modal.form.tag) {modal.form.tag.forEach(function (value) {if (value) {formData.append(tag, value);}});}if (modal.form.imageFile) {formData.append(cover, modal.form.imageFile);}formData.append(description, modal.form.description || );formData.append(price, modal.form.price || );if (modal.form.mobile) {formData.append(mobile, modal.form.mobile);}if (modal.form.zongzhi) {formData.append(zongzhi, modal.form.zongzhi);}if (modal.form.email) {formData.append(email, modal.form.email);}if (modal.form.location) {formData.append(location, modal.form.location);}if (modal.form.status) {formData.append(status, modal.form.status);}if (modal.editFlag) {updateApi({id: modal.form.id,},formData,).then((res) {hideModal();getDataList();}).catch((err) {console.log(err);message.error(err.msg || 操作失败);});} else {createApi(formData).then((res) {hideModal();getDataList();}).catch((err) {console.log(err);message.error(err.msg || 操作失败);});}}).catch((err) {console.log(不能为空);});};const handleCancel () {hideModal();};// 恢复表单初始状态const resetModal () {myform.value?.resetFields();fileList.value [];};// 关闭弹窗const hideModal () {modal.visile false;};
/scriptstyle scoped langless.page-view {min-height: 100%;background: #fff;padding: 24px;display: flex;flex-direction: column;}.table-operations {margin-bottom: 16px;text-align: right;}.table-operations button {margin-right: 8px;}
/style
这就是社团管理功能的实现流程其它的功能管理实现一模一样的。按照这个流程编写即可。
重要模块实现
分页实现
基于ant-design框架的a-table的分页插件。
// 分页变量const data reactive({dataList: [],loading: false,keyword: ,selectedRowKeys: [] as any[],pageSize: 10,page: 1,});// 分页插件
:pagination{size: default,current: data.page,pageSize: data.pageSize,onChange: (current) (data.page current),showSizeChanger: false,showTotal: (total) 共${total}条数据,}
请求工具实现
前端的请求工具是基于axios开发的位于utils的http文件夹中。封装了request请求和拦截器。
const service: AxiosInstance axios.create({// baseURL: import.meta.env.BASE_URL ,baseURL: BASE_URL ,timeout: 15000,
});// axios实例拦截请求
service.interceptors.request.use((config: InternalAxiosRequestConfig) {config.headers.ADMINTOKEN localStorage.getItem(ADMIN_USER_TOKEN);config.headers.TOKEN localStorage.getItem(USER_TOKEN);return config;},(error: AxiosError) {return Promise.reject(error);},
);// axios实例拦截响应
service.interceptors.response.use((response: AxiosResponse) {if (response.status 200) {if (response.data.code 0 || response.data.code 200) {return response;} else {return Promise.reject(response.data);}} else {return Promise.reject(response.data);}},// 请求失败(error: any) {console.log(error.response.status);if (error.response.status 404) {// todo} else if (error.response.status 403) {// todo}return Promise.reject(error);},
);
权限控制模块
权限控制使用了BaseAuthentication实现的具体代码可参考authentication.py
from rest_framework import exceptions
from rest_framework.authentication import BaseAuthentication
from myapp.models import User# 接口认证
class AdminTokenAuthtication(BaseAuthentication):def authenticate(self, request):adminToken request.META.get(HTTP_ADMINTOKEN)print(检查adminToken adminToken)users User.objects.filter(admin_tokenadminToken)判定条件1. 传了adminToken 2. 查到了该帐号 3. 该帐号是管理员或演示帐号if not adminToken or len(users) 0 or users[0].role 2:raise exceptions.AuthenticationFailed(AUTH_FAIL_END)else:print(adminToken验证通过)
路由模块实现
前端的路由是基于vue-router框架实现的路由文件位于src的rooter的root.js文件中。预览如下 {path: /admin,name: admin,redirect: /admin/thing,component: () import(//views/admin/main.vue),children: [{ path: overview, name: overview, component: () import(//views/admin/overview.vue) },{ path: order, name: order, component: () import(//views/admin/order.vue) },{ path: thing, name: thing, component: () import(//views/admin/thing.vue) },{ path: comment, name: comment, component: () import(//views/admin/comment.vue) },{ path: user, name: user, component: () import(//views/admin/user.vue) },{ path: classification, name: classification, component: () import(//views/admin/classification.vue) },{ path: tag, name: tag, component: () import(//views/admin/tag.vue) },{ path: ad, name: ad, component: () import(//views/admin/ad.vue) },{ path: notice, name: notice, component: () import(//views/admin/notice.vue) },{ path: loginLog, name: loginLog, component: () import(//views/admin/login-log.vue) },{ path: opLog, name: opLog, component: () import(//views/admin/op-log.vue) },{ path: errorLog, name: errorLog, component: () import(//views/admin/error-log.vue) },{ path: sysInfo, name: sysInfo, component: () import(//views/admin/sys-info.vue) },]},限速功能实现
限流(Throttle)就是限制客户端对API 的调用频率是API开发者必须要考虑的因素。比如个别客户端(比如爬虫程序)短时间发起大量请求超过了服务器能够处理的能力将会影响其它用户的正常使用。又或者某个接口占用数据库资源比较多如果同一时间该接口被大量调用服务器可能会陷入僵死状态。为了保证API服务的稳定性并防止接口受到恶意用户的攻击我们必须要对我们的API服务进行限流。
我们使用了django的AnonRateThrottle限流类来实现的。可以参见myapp的auth目录下的MyRateThrottle.py文件
class MyRateThrottle(AnonRateThrottle):THROTTLE_RATES {anon: 2/min} # 限流每分钟只能请求2次当某个api接口需要限流的时候只需要添加注解即可如下所示
api_view([POST])
throttle_classes([MyRateThrottle]) # 限流注解
def create(request):serializer CommentSerializer(datarequest.data)if serializer.is_valid():serializer.save()return APIResponse(code0, msg创建成功, dataserializer.data)else:print(serializer.errors)return APIResponse(code1, msg创建失败)常见问题
数据库版本有要求吗
需要mysql 5.7以上
前端 npm install 失败怎么办
使用国内镜像安装设置命令为
npm config set registry https://registry.npm.taobao.org提示演示账号无法操作怎么办
将用户的权限提高修改b_user表的role字段
如何更换后端请求地址
修改store文件夹下的constants.js文件中的BASE_URL改成你自己的后端地址
如何新增页面
在views文件夹下创建新的vue文件写入界面代码然后在router的root.js中添加路由即可。