Django学习笔记-用户名密码登录

  1. 1. 扩充Django数据库
  2. 2. 实现获取用户信息
  3. 3. 渲染登录与注册界面
  4. 4. 实现登录与登出功能
  5. 5. 实现注册功能
  6. 6. 修改获取用户信息

本节内容是使用 Django 实现用户的注册与登录等后端功能。

1. 扩充Django数据库

首先我们先在 settings.py 中修改:DEBUG = True,否则如果服务器端的代码报错时前端不会显示报错详细信息。

Django 自带一个账号系统,在网址后面添加后缀 /admin 即可访问管理员界面,登录之前的超级管理员账号,进入管理员界面后其中的 Users 界面就是自带的账号系统。

其中可以填写每个用户的姓名和邮箱,Active 表示用户是否被封,不勾选即无法登录;Staff status 表示用户是否能进入到后台管理页面;Superuser status 表示用户是否具有超级管理员的权限。

这个自带的账号系统不能满足我们的需求,例如需要存储用户的头像,该数据库就需要进行扩充。

我们要在 djangoapp/game/models 目录下创建我们所需的表,即创建类似之前提到的 Users,我们在该目录中新建一个 player 目录,然后进入该目录,记得需要先创建一个 __init__.py 文件。

接着我们创建 player.py 用来存储 player 这个数据表的信息,创建类时需要继承基类 django.db.models.Model(开发时有个小 Tips,如果忘记一些关键字怎么写可以在项目根目录执行 python3 manage.py shell,进入 IPython 交互功能,然后输入代码即具有补全功能):

1
2
3
4
5
6
7
8
9
10
from django.db import models
from django.contrib.auth.models import User

# Player有两个关键字,user表示是和哪个User对应的,avatar表示头像
class Player(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE) # 当删除User时也将其关联的Player一块删掉
avatar = models.URLField(max_length=256, blank=True) # 头像用链接存

def __str__(self): # 显示每个Player的数据
return str(self.user)

创建好数据表后如果希望让我们的数据表出现在管理员界面,需要将它注册到管理员页面,在 game 目录下可以看到一个 admin.py 文件,对其进行修改:

1
2
3
4
5
from django.contrib import admin
from game.models.player.player import Player # 将表导进来

# Register your models here.
admin.site.register(Player)

每次对数据表的定义更新后都需要执行以下两句指令(在项目根目录):

1
2
python3 manage.py makemigrations
python3 manage.py migrate

然后我们重启一下项目:uwsgi --ini scripts/uwsgi.ini,即可看到新创建的 Player 表,在右上角的 ADD PLAYER 选项中即可添加 Player。

从这个例子即可看出数据库中的 Table 对应 Django 中的 Class,Table 中的每一条数据就对应 Class 中的每一个对象。

2. 实现获取用户信息

假设我们将网页刷新后,Clinet 先向后台服务器(Server)发送一个请求获得当前玩家的信息 getinfo,后台一种是返回用户名和头像,还有一种是返回未登录,现在我们先默认每次都返回玩家的用户名和头像,每次写一个函数时需要写三个部分:views 表示调用数据库的逻辑、urls 表示路由、js 实现调用。

由于有多个前端,因此后端在接收请求的时候需要知道是哪个前端,需要对 AcGame 类进行修改,让其多传入一个参数 acwingos,如果在 AcWing 打开该项目则会传入该参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export class AcGame {
constructor(id, acwingos) {
this.id = id;
this.$ac_game = $('#' + id); // jQuery通过id找对象的方式
this.acwingos = acwingos; // 通过AcWing打开时会传入此参数

this.menu = new AcGameMenu(this);
this.playground = new AcGamePlayground(this);

this.start();
}

start() {
}
}

进入 views 目录,我们将所有用户的信息全部放到 settings 目录中,在 settings 目录创建一个 getinfo.py 文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from django.http import JsonResponse
from game.models.player.player import Player

def getinfo_acapp(request):
player = Player.objects.all()[0] # 先默认返回第一个玩家的信息
return JsonResponse({
'result': 'success', # 查询结果
'username': player.user.username,
'avatar': player.avatar,
})

def getinfo_web(request):
player = Player.objects.all()[0]
return JsonResponse({
'result': 'success',
'username': player.user.username,
'avatar': player.avatar,
})

def getinfo(request):
platform = request.GET.get('platform') # 是哪个平台发起的请求
if platform == 'ACAPP':
return getinfo_acapp(request)
else:
return getinfo_web(request)

然后进入 urls/settings 目录,修改 index.py 文件:

1
2
3
4
5
6
from django.urls import path
from game.views.settings.getinfo import getinfo

urlpatterns = [
path('getinfo/', getinfo, name='settings_getinfo')
]

现在我们即可访问 https://<项目IP地址>/settings/getinfo/ 查看效果。

最后我们需要在游戏的菜单界面之前添加一个界面判断用户是否登录,先将 AcGameMenu 类在初始化操作中 hide,然后进入 /djangoapp/game/static/js/src/settings 目录中创建 zbase.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class Settings {
constructor(root) {
this.root = root;
this.platform = 'WEB'; // 默认为Web前端
if (this.root.acwingos) this.platform = 'ACAPP';

this.start();
}

start() { // 在初始化时需要从服务器端获取用户信息
this.getinfo();
}

register() { // 打开注册界面
}

login() { // 打开登录界面
}

getinfo() {
let outer = this;
$.ajax({
url: 'https://app4007.acapp.acwing.com.cn/settings/getinfo/', // 用AcWing部署
// url: 'http://8.130.54.44:8000/settings/getinfo/', // 用云服务器部署
type: 'GET',
data: {
platform: outer.platform,
},
success: function(resp) { // 调用成功的回调函数,返回的Json字典会传给resp
console.log(resp); // 控制台输出查看结果
if (resp.result === 'success') {
outer.hide();
outer.root.menu.show();
} else { // 如果未登录则需要弹出登录界面
outer.login();
}
}
});
}

hide() {
}

show() {
}
}

然后在 AcGame 类中创建 Settings 对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export class AcGame {
constructor(id, acwingos) {
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.acwingos = acwingos;

this.start();
}

start() {
}
}

此时访问网站即可看到控制台的输出信息。

此时项目的执行顺序为:创建 Settings 类的对象时先执行构造函数,接着会执行 start 中的 getinfo 函数,会向后端(https://app4007.acapp.acwing.com.cn/settings/getinfo/)发一个请求,然后路由会找到 views.settings.getinfo 文件中的 getinfo 函数,然后判断 platformWEB,最后通过 getinfo_web 返回用户名和用户头像到 resp 中。

现在我们来判断用户是否登录,修改 views/settings 目录中的 getinfo.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from django.http import JsonResponse
from game.models.player.player import Player

def getinfo_acapp(request):
...

def getinfo_web(request):
user = request.user
if not user.is_authenticated:
return JsonResponse({
'result': 'not login',
})
else:
player = Player.objects.all()[0]
return JsonResponse({
'result': 'success',
'username': player.user.username,
'avatar': player.avatar,
})

def getinfo(request):
...

然后我们需要将用户的信息存下来,将头像渲染到小球里,首先在 js/src/settings 目录中修改 zbase.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class Settings {
constructor(root) {
...
this.username = ''; // 初始用户信息为空
this.avatar = '';

this.start();
}

start() { // 在初始化时需要从服务器端获取用户信息
this.getinfo();
}

register() { // 打开注册界面
}

login() { // 打开登录界面
}

getinfo() {
let outer = this;
$.ajax({
url: 'https://app4007.acapp.acwing.com.cn/settings/getinfo/', // 用AcWing部署
// url: 'http://8.130.54.44: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;
...
} else { // 如果未登录则需要弹出登录界面
outer.login();
}
}
});
}

hide() {
}

show() {
}
}

然后在 Player 类中渲染用户的头像:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class Player extends AcGameObject {
constructor(playground, x, y, radius, color, speed, is_me) {
...
if (this.is_me) { // 用户自己的头像从服务器端获取
this.img = new Image();
this.img.src = this.playground.root.settings.avatar;
}
}

start() {
...
}

add_listening_events() {
...
}

// 计算两点之间的欧几里得距离
get_dist(x1, y1, x2, y2) {
...
}

// 向(tx, ty)位置发射火球
shoot_fireball(tx, ty) {
...
}

move_to(tx, ty) {
...
}

is_attacked(theta, damage) { // 被攻击到
...
}

update() {
...
}

render() {
if (this.is_me) {
this.ctx.save();
this.ctx.beginPath();
this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
this.ctx.stroke();
this.ctx.clip();
this.ctx.drawImage(this.img, this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2);
this.ctx.restore();
} else {
this.ctx.beginPath();
// 角度从0画到2PI,是否逆时针为false
this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
this.ctx.fillStyle = this.color;
this.ctx.fill();
}
}
}

3. 渲染登录与注册界面

首先我们下载 AcWing 一键登录所需要的图标资源,进入 static/image/settings 目录执行以下指令:

1
2
wget https://cdn.acwing.com/media/article/image/2021/11/18/1_ea3d5e7448-logo64x64_2.png
mv 1_ea3d5e7448-logo64x64_2.png acwing_logo.png

然后完善 Settings 类渲染登录与注册界面并且实现两个界面的跳转功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
class Settings {
constructor(root) {
this.root = root;
this.platform = 'WEB'; // 默认为Web前端
if (this.root.acwingos) this.platform = 'ACAPP';
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>
<br> <!-- inline格式可能有bug,需要加一行回车 -->
<div class='ac_game_settings_acwingoption'>
<img width='30' src='https://app4007.acapp.acwing.com.cn/static/image/settings/acwing_logo.png'>
<br>
<div>AcWing Login</div>
</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();
});
}

add_listening_events_register() {
let outer = this;
this.$register_login.click(function() {
outer.login();
});
}

register() { // 打开注册界面
this.$login.hide();
this.$register.show();
}

login() { // 打开登录界面
this.$register.hide();
this.$login.show();
}

getinfo() {
let outer = this;
$.ajax({
url: 'https://app4007.acapp.acwing.com.cn/settings/getinfo/', // 用AcWing部署
// url: 'http://8.130.54.44: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 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
.ac_game_menu {
width: 100%;
height: 100%;
background-image: url('/static/image/menu/background.png'); /* 注意不用带公网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/background.png');
background-size: 100% 100%;
user-select: none;
}

.ac_game_settings_login {
height: 41vh;
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_acwingoption {
display: block;
height: 8vh;
}

.ac_game_settings_acwingoption > img {
display: block;
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
cursor: pointer;
}

.ac_game_settings_acwingoption > div {
display: block;
color: white;
font-size: 1.2vh;
text-align: center;
padding-top: 1vh;
}

.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;
}

4. 实现登录与登出功能

实现登录与登出功能我们同样要编写 viewsurls 以及 js 文件,首先在 game/views/settings 目录下创建 login.py 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from django.contrib.auth import authenticate, login
from django.http import JsonResponse

def mylogin(request):
data = request.GET
username = data.get('username')
password = data.get('password')
user = authenticate(username=username, password=password)
if not user:
return JsonResponse({
'result': '用户名或密码不正确',

})
login(request, user)
return JsonResponse({
'result': 'success',
})

然后进入 game/urls/settings 目录修改 index.py

1
2
3
4
5
6
7
8
from django.urls import path
from game.views.settings.getinfo import getinfo
from game.views.settings.login import mylogin

urlpatterns = [
path('getinfo/', getinfo, name='settings_getinfo'),
path('login/', mylogin, name='settings_login'),
]

此时重启一下项目后访问 https://<公网IP>/settings/login/ 即可看到返回结果。

现在我们实现一下登出函数,在 game/views/settings 目录下创建 logout.py 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
from django.contrib.auth import logout
from django.http import JsonResponse

def mylogout(request):
user = request.user
if not user.is_authenticated:
return JsonResponse({
'result': 'success',
})
logout(request)
return JsonResponse({
'result': 'success',
})

然后进入 game/urls/settings 目录修改 index.py

1
2
3
4
5
6
7
8
9
10
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

urlpatterns = [
path('getinfo/', getinfo, name='settings_getinfo'),
path('login/', mylogin, name='settings_login'),
path('logout/', mylogout, name='settings_logout'),
]

此时重启一下项目后在登录状态下访问 https://<公网IP>/settings/logout/ 即可登出。

然后我们在 Settings 类中实现登录登出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
class Settings {
constructor(root) {
...
}

start() { // 在初始化时需要从服务器端获取用户信息
...
}

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();
});
}

login_on_remote() { // 在远程服务器上登录
let outer = this;
let username = this.$login_username.val();
let password = this.$login_password.val();
this.$login_errormessage.empty(); // 先清空报错信息

$.ajax({
url: 'https://app4007.acapp.acwing.com.cn/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() { // 在远程服务器上注册
}

logout_on_remote() { // 在远程服务器上登出
if (this.platform === 'ACAPP') { // AcApp应该是直接关闭窗口退出
this.root.acwingos.api.window.close(); // 调用AcWing接口关闭窗口
} else {
$.ajax({
url: 'https://app4007.acapp.acwing.com.cn/settings/logout/',
type: 'GET',
success: function(resp) {
console.log(resp);
if (resp.result === 'success') {
location.reload();
}
}
});
}
}

register() { // 打开注册界面
...
}

login() { // 打开登录界面
...
}

getinfo() {
...
}

hide() {
...
}

show() {
...
}
}

其中登出函数 logout_on_remote 需要在 AcGameMenu 类中调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class AcGameMenu {
constructor(root) { // root用来传AcGame对象
this.root = root;
this.$menu = $(`
<div class='ac_game_menu'>
<div class='ac_game_menu_btgroup'>
...
<div class='ac_game_menu_btgroup_bt ac_game_menu_btgroup_bt_settings'>
登出
</div>
</div>
</div>
`);
...
this.$settings = this.$menu.find('.ac_game_menu_btgroup_bt_settings');

this.start();
}

start() {
...
}

// 给按钮绑定监听函数
add_listening_events() {
let outer = this;
...
this.$settings.click(function() {
outer.root.settings.logout_on_remote();
});
}

// 显示menu界面
show() {
...
}

// 关闭menu界面
hide() {
...
}
}

5. 实现注册功能

首先在 game/views/settings 目录下创建 register.py 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from django.contrib.auth import login
from django.contrib.auth.models import User
from django.http import JsonResponse
from game.models.player.player import Player

def register(request):
data = request.GET
username = data.get('username', '').strip() # 如果没有的话返回空,且过滤掉空格
password = data.get('password', '').strip()
confirm_password = data.get('confirm_password', '').strip()
if not username or not password: # 用户名或密码为空
return JsonResponse({
'result': 'Username or password can\'t be empty!',
})
elif password != confirm_password: # 两次密码不一致
return JsonResponse({
'result': 'Password inconsistency!'
})
elif User.objects.filter(username=username).exists(): # 用户名已存在
return JsonResponse({
'result': 'Username has existed!'
})
user = User(username=username)
user.set_password(password)
user.save()
Player.objects.create(user=user, avatar='https://cdn.acwing.com/media/article/image/2021/11/18/1_ea3d5e7448-logo64x64_2.png')
login(request, user)
return JsonResponse({
'result': 'success',
})

然后进入 game/urls/settings 目录修改 index.py

1
2
3
4
5
6
7
8
9
10
11
12
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'),
]

此时重启一下项目后访问 https://<公网IP>/settings/register/ 即可看到返回结果。

最后修改前端 Settings 类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
class Settings {
constructor(root) {
...
}

start() { // 在初始化时需要从服务器端获取用户信息
...
}

add_listening_events() { // 绑定监听函数
...
}

add_listening_events_login() {
...
}

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() { // 在远程服务器上登录
...
}

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: 'https://app4007.acapp.acwing.com.cn/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() { // 在远程服务器上登出
...
}

register() { // 打开注册界面
...
}

login() { // 打开登录界面
...
}

getinfo() {
...
}

hide() {
...
}

show() {
...
}
}

6. 修改获取用户信息

之前我们是默认返回第一个用户的信息,我们对 game/views/settings 目录下的 getinfo.py 文件进行修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from django.http import JsonResponse
from game.models.player.player import Player

def getinfo_acapp(request):
...

def getinfo_web(request):
user = request.user
if not user.is_authenticated:
return JsonResponse({
'result': 'not login',
})
else:
player = Player.objects.get(user=user) # 获取user的player信息
return JsonResponse({
'result': 'success',
'username': player.user.username,
'avatar': player.avatar,
})

def getinfo(request):
platform = request.GET.get('platform') # 是哪个平台发起的请求
if platform == 'ACAPP':
return getinfo_acapp(request)
# elif platform == 'WEB':
else:
return getinfo_web(request)

上一章:Django学习笔记-部署Nginx与对接AcApp

下一章:Django学习笔记-Web端授权AcWing一键登录