截止到上一章节:Django 学习笔记-Web 端授权 AcWing 一键登录,我们的项目一直是部署在云服务器上,包括编写代码以及调试运行也是在云服务器上,现在我们尝试将其放回本地运行。
CONTENTS
- 1. 将项目传到本地
- 2. 虚拟环境配置
- 3. 修改项目相关文件
1. 将项目传到本地
这一步可以使用 Git 也可以使用 SCP,由于之前项目上传在 AcGit 上,只能在 AC Terminal 中拉取,因此使用 SCP 远程传输:
scp -r -P 20000 asanosaki@<公网IP>:djangoapp . # 在要存放项目的目录执行该指令
2. 虚拟环境配置
我们需要先配置一个和云服务上相同的虚拟环境,首先在 VS Code 中打开该项目并且打开终端,在项目根目录下创建虚拟环境:
python -m venv venv
虚拟环境创建成功之后,一般不会自动启用,所以需要启用它,进入 env/Scripts
目录运行脚本 Activate.ps1
:
cd .\venv\Scripts\
.\Activate.ps1
此时可以看到命令行首部多了 (venv)
,说明已进入虚拟环境,然后选择解释器即可:
现在我们安装所需的环境:
pip install django
3. 修改项目相关文件
首先修改一下我们的打包脚本 compress_game_js.sh
:
#! /bin/bash
JS_PATH=../game/static/js/
JS_PATH_DIST=${JS_PATH}dist/
JS_PATH_SRC=${JS_PATH}src/
find ${JS_PATH_SRC} -type f -name '*.js' | sort | xargs cat > ${JS_PATH_DIST}game.js
然后打开 Git Bash,进入 scripts
文件夹即可运行脚本:
sh compress_game_js.sh
然后将 djangoapp/settings.py
中的 Redis 配置删除,即删除以下这段话:
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
},
},
}
USER_AGENTS_CACHE = 'default'
同样在该文件中需要将 localhost
添加到 ALLOWED_HOSTS
中:
ALLOWED_HOSTS = ["8.130.54.44", "app4007.acapp.acwing.com.cn", "localhost"]
然后将 AcWing 一键授权登录的相关文件夹删除:game/views/settings/acwing
、game/urls/settings/acwing
,然后修改 urls/settings/index.py
中的路由:
from django.urls import path
from game.views.settings.getinfo import getinfo
from game.views.settings.login import mylogin
from game.views.settings.logout import mylogout
from game.views.settings.register import register
urlpatterns = [
path('getinfo/', getinfo, name='settings_getinfo'),
path('login/', mylogin, name='settings_login'),
path('logout/', mylogout, name='settings_logout'),
path('register/', register, name='settings_register'),
]
修改 AcGame
类,去掉 AcWingOS API,且改为非模块化引入 JS 方式,即去掉 export
关键字:
class AcGame {
constructor(id) {
this.id = id;
this.$ac_game = $('#' + id); // jQuery通过id找对象的方式
this.settings = new Settings(this);
this.menu = new AcGameMenu(this);
this.playground = new AcGamePlayground(this);
this.start();
}
start() {
}
}
同时前端的 web.html
文件也需要修改:
{% load static %}
<head>
<link rel="stylesheet" href="{% static 'css/jquery-ui.min.css' %}">
<script src="{% static 'js/jquery-3.6.1.min.js' %}"></script>
<link rel="stylesheet" href="{% static 'css/game.css' %}">
<script src="{% static 'js/dist/game.js' %}"></script>
</head>
<body style="margin: 0">
<div id="ac_game_1"></div>
<script>
$(document).ready(function() {
let ac_game = new AcGame("ac_game_1");
});
</script>
</body>
最后修改 Settings
类,去掉 AcWing 一键登录功能,且修改 ajax
请求的地址:
class Settings {
constructor(root) {
this.root = root;
this.platform = 'WEB'; // 默认为Web前端
this.username = ''; // 初始用户信息为空
this.avatar = '';
this.$settings = $(`
<div class='ac_game_settings'>
<div class='ac_game_settings_login'>
<div class='ac_game_settings_title'>
Login
</div>
<div class='ac_game_settings_username'>
<div class='ac_game_settings_item'>
<input type='text' placeholder='Username'>
</div>
</div>
<div class='ac_game_settings_password'>
<div class='ac_game_settings_item'>
<input type='password' placeholder='Password'>
</div>
</div>
<div class='ac_game_settings_submit'>
<div class='ac_game_settings_item'>
<button>Login</button>
</div>
</div>
<div class='ac_game_settings_errormessage'>
</div>
<div class='ac_game_settings_option'>
Register
</div>
</div>
<div class='ac_game_settings_register'>
<div class='ac_game_settings_title'>
Register
</div>
<div class='ac_game_settings_username'>
<div class='ac_game_settings_item'>
<input type='text' placeholder='Username'>
</div>
</div>
<div class='ac_game_settings_password ac_game_settings_password_first'>
<div class='ac_game_settings_item'>
<input type='password' placeholder='Password'>
</div>
</div>
<div class='ac_game_settings_password ac_game_settings_password_second'>
<div class='ac_game_settings_item'>
<input type='password' placeholder='Confirm Password'>
</div>
</div>
<div class='ac_game_settings_submit'>
<div class='ac_game_settings_item'>
<button>Register</button>
</div>
</div>
<div class='ac_game_settings_errormessage'>
</div>
<div class='ac_game_settings_option'>
Login
</div>
</div>
</div>
`);
this.$login = this.$settings.find('.ac_game_settings_login');
this.$login_username = this.$login.find('.ac_game_settings_username input');
this.$login_password = this.$login.find('.ac_game_settings_password input');
this.$login_submit = this.$login.find('.ac_game_settings_submit button');
this.$login_errormessage = this.$login.find('.ac_game_settings_errormessage');
this.$login_register = this.$login.find('.ac_game_settings_option');
this.$login.hide();
this.$register = this.$settings.find('.ac_game_settings_register');
this.$register_username = this.$register.find('.ac_game_settings_username input');
this.$register_password = this.$register.find('.ac_game_settings_password_first input');
this.$register_confirm_password = this.$register.find('.ac_game_settings_password_second input');
this.$register_submit = this.$register.find('.ac_game_settings_submit button');
this.$register_errormessage = this.$register.find('.ac_game_settings_errormessage');
this.$register_login = this.$register.find('.ac_game_settings_option')
this.$register.hide();
this.root.$ac_game.append(this.$settings);
this.start();
}
start() { // 在初始化时需要从服务器端获取用户信息
this.getinfo();
this.add_listening_events();
}
add_listening_events() { // 绑定监听函数
this.add_listening_events_login();
this.add_listening_events_register();
}
add_listening_events_login() {
let outer = this;
this.$login_register.click(function() {
outer.register();
});
this.$login_submit.click(function() {
outer.login_on_remote();
});
}
add_listening_events_register() {
let outer = this;
this.$register_login.click(function() {
outer.login();
});
this.$register_submit.click(function() {
outer.register_on_remote();
});
}
login_on_remote() { // 在远程服务器上登录
let outer = this;
let username = this.$login_username.val();
let password = this.$login_password.val();
this.$login_errormessage.empty(); // 先清空报错信息
$.ajax({
url: 'http://localhost:8000/settings/login/',
type: 'GET',
data: {
username: username,
password: password,
},
success: function(resp) {
console.log(resp);
if (resp.result === 'success') { // 登录成功
location.reload(); // 刷新页面
} else { // 登录失败
outer.$login_errormessage.html(resp.result); // 显示报错信息
}
}
});
}
register_on_remote() { // 在远程服务器上注册
let outer = this;
let username = this.$register_username.val();
let password = this.$register_password.val();
let confirm_password = this.$register_confirm_password.val();
this.$register_errormessage.empty();
$.ajax({
url: 'http://localhost:8000/settings/register/',
type: 'GET',
data: {
username: username,
password: password,
confirm_password: confirm_password,
},
success: function(resp) {
console.log(resp);
if (resp.result === 'success') {
location.reload();
} else {
outer.$register_errormessage.html(resp.result);
}
}
});
}
logout_on_remote() { // 在远程服务器上登出
if (this.platform === 'ACAPP') return false; // AcApp应该是直接关闭窗口退出
$.ajax({
url: 'http://localhost:8000/settings/logout/',
type: 'GET',
success: function(resp) {
console.log(resp);
if (resp.result === 'success') {
location.reload();
}
}
});
}
register() { // 打开注册界面
this.$login.hide();
this.$register.show();
}
login() { // 打开登录界面
this.$register.hide();
this.$login.show();
}
getinfo() {
let outer = this;
$.ajax({
url: 'http://localhost:8000/settings/getinfo/',
type: 'GET',
data: {
platform: outer.platform,
},
success: function(resp) { // 调用成功的回调函数,返回的Json字典会传给resp
console.log(resp); // 控制台输出查看结果
if (resp.result === 'success') {
outer.username = resp.username;
outer.avatar = resp.avatar;
outer.hide();
outer.root.menu.show();
} else { // 如果未登录则需要弹出登录界面
outer.login();
}
}
});
}
hide() {
this.$settings.hide();
}
show() {
this.$settings.show();
}
}
顺带还需要修改一下 game.css
:
.ac_game_menu {
width: 100%;
height: 100%;
background-image: url('/static/image/menu/background2.jpeg'); /* 注意不用带公网IP */
background-size: 100% 100%;
user-select: none;
}
.ac_game_menu_btgroup {
width: 20vw;
position: relative;
top: 30%;
left: 20%;
}
.ac_game_menu_btgroup_bt {
height: 7vh;
width: 15vw;
color: white;
font-size: 3vh;
line-height: 7vh;
font-style: italic;
cursor: pointer;
text-align: center;
background-color: rgba(39, 21, 28, 0.6);
border-radius: 10px;
letter-spacing: 0.5vw;
}
.ac_game_menu_btgroup_bt:hover {
transform: scale(1.2);
transition: 100ms;
}
.ac_game_playground {
height: 100%;
width: 100%;
user-select: none;
}
.ac_game_settings {
width: 100%;
height: 100%;
background-image: url('/static/image/menu/background2.jpeg');
background-size: 100% 100%;
user-select: none;
}
.ac_game_settings_login {
height: 32vh;
width: 20vw;
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(0, 0, 0, 0.7);
border-radius: 5px;
}
.ac_game_settings_register {
height: 39vh;
width: 20vw;
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(0, 0, 0, 0.7);
border-radius: 5px;
}
.ac_game_settings_title {
color: white;
font-size: 3.5vh;
text-align: center;
height: 7vh;
line-height: 7vh;
}
.ac_game_settings_username {
display: block;
height: 7vh;
}
.ac_game_settings_password {
display: block;
height: 7vh;
}
.ac_game_settings_submit {
display: block;
height: 7vh;
}
.ac_game_settings_errormessage {
color: red;
font-size: 1.5vh;
display: inline;
float: left;
padding-left: 1vw;
}
.ac_game_settings_option {
color: white;
font-size: 1.5vh;
display: inline;
float: right;
padding-right: 1vw;
cursor: pointer;
}
.ac_game_settings_item {
width: 100%;
height: 100%;
}
.ac_game_settings_item > input {
width: 90%;
line-height: 3vh;
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.ac_game_settings_item > button {
color: black;
width: 30%;
line-height: 3vh;
font-size: 2vh;
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgb(199, 237, 204);
border-radius: 7px;
cursor: pointer;
}
最后我们将 .git
文件夹删除,重新上传至 Github(先创建一个仓库 Small_Ball_Fight
):
git init
git remote add origin git@github.com:AsanoSaki/Small_Ball_Fight.git
git add .
git commit -m "create small ball fight"
git push --set-upstream origin master