五、创建账号系统

这是实现后的效果:

        

账号系统展示

----------创建账号系统

1.首先运行后端进程:ctrl + r 输入uws即可快捷找到历史输入命令
    uwsgi --ini scripts/uwsgi.ini

    然后将全局配置文件settings中的DEBUG修改成True,这样才能在前端网页报错时方便调试

2.在根目录acapp下,可以创建一个超级用户:
    python3 manage.py createsuperuser
    这样,就可以用网址/admin进入后台管理,可以管理用户

    django系统自带了一个用户系统Users,但信息有限,我们想要加上一个头像,就需要利用django自带的数据库进行扩充,步骤如下:
        进入/acapp/game/models,创建所有的表:
            mkdir player #创建一个文件夹放置所有关于玩家的表,并进入
            touch __init__.py #每个python文件夹都需要
            vim player.py #用来存储player这个数据表的信息

            django里创建一个数据表就是定义一个class,如下:
                 `  from django.db import models#继承django数据库的基类
                    from django.contrib.auth.models import User #还需要用到User这个类


                    class Player(models.Model):#每一个定义的类,都需要继承自models.Model这个类
                        #每一个Player都唯一对应一个user,如下定义(对应哪个表,当user删除时需要执行什么函数)
                        user = models.OneToOneField(User, on_delete=models.CASCADE)#user删除时,把他关联的Player一并删掉
                        photo = models.URLField(max_length = 256, blank = True)#头像的话,(需要存储一个链接,需要定义一个最大长度和是否可以为空)

                        def __str__(self):#显示每一个Player时,显示的是什么                                                                                                                                      
                            return str(self.user)` 

                这样就定义好了Player新的数据表,里面有两个关键字,user表示与谁一一对应,photo表示头像
            小技巧:在django家目录下,输入python3 manage.py shell,可以进入一个交互模式,忘记的命令可以在此进行补全回忆

        若想让我们创建的数据表出现在管理员页面,还需要在/acapp/game/admin.py里注册进去,如下:
             `  from django.contrib import admin
                from game.models.player.player import Player#先引用进来,路由

                admin.site.register(Player)#注册` 

        然后保存,每一对数据库的数据表进行修改时,都需要执行两个命令:
            python3 manage.py makemigrations 
            python3 manage.py migrate,

        执行完之后,我们定义的表就会被应用到服务器里

3.登录流程:
    用户每次在浏览器(clent)刷新的时候,先向后台服务器(server)发送一个请求,获取当前玩家的信息(getinfo),server会返回两个信息(username和photo)或者返回未登录,

    未来网站会运行在不同的平台上,比如浏览器和acapp或者小程序等等,在不同平台执行的行为可能不同,所以我们需要知道当前运行在什么平台上,不同平台的处理逻辑应该不同

    于是对于之前的js代码则需要进行修改:
        game/static/js/src/zbase.js下:
        ...AcGame {
            constuctor(id, AcWingOS)  //用来识别登录平台
            ...
            this.AcWingOS = AcWingOS; //保存下来

            ...
        }

    我们先默认已登录,先写返回第一名玩家信息这个函数:
            这里去写需要前后端一起写,每次写一个函数,都需要实现三个东西(views:调用数据库的逻辑,urls:路由,js:实现调用):
                一般先写views, 

    未来设置里可以修改我们的信息,所以我们将信息放到settings里:
        创建game/views/settings/getinfo.py,如下:
               `from django.http import JsonResponse#每次返回到这里
                from game.models.player.player import Player#引入刚才创建的数据库

                def getinfo_acapp(request):#处理acapp端的请求
                    player = Player.objects.all()[0]
                    return JsonResponse({
                        'result': "success",
                        'username': player.user.username,
                        'photo': player.photo,
                    })  

                def getinfo_web(request): #处理web端的请求
                    player = Player.objects.all()[0]#取出第一位玩家的信息
                    return JsonResponse({#返回信息
                        'result': "success",
                        'username': player.user.username,
                        'photo': player.photo,
                    })  

                def getinfo(request):#处理请求
                    platform = request.GET.get('platform') #判断是从哪个平台传过来的
                    if platform == "ACAPP":                                                                                                                                                                  
                        return getinfo_acapp(request)
                    else:
                        return getinfo_web(request)` 

    写完views,写urls,
        game/urls/settings/index.py,如下:
               `from django.urls import path
                from game.views.settings.getinfo import getinfo#将刚刚写的函数引入

                #写路由
                urlpatterns = [ 
                    path("getinfo/", getinfo, name = "settings_getinfo"),
                ] ` 
        写完之后,重启服务,访问网址/settings/getinfo,若成功看到返回值,则成功了,开始写js:
            在菜单界面之前加一个登录界面:
                class AcGameMenu {
                constructor(root) {
                    this.root = root;
                    this.$menu = $(`
                <div class="ac-game-menu">
                    <div class="ac-game-menu-field">
                        <div class="ac-game-menu-field-item ac-game-menu-field-item-single-mode">
                            单人模式
                        </div>
                        <br>
                        <div class="ac-game-menu-field-item ac-game-menu-field-item-multi-mode">
                            多人模式
                        </div>
                        <br>
                        <div class="ac-game-menu-field-item ac-game-menu-field-item-settings">
                            退出 
                        </div>
                    </div>
                </div>
                `);
                        this.$menu.hide(); //默认先关闭
                        this.root.$ac_game.append(this.$menu);
                        this.$single_mode = this.$menu.find('.ac-game-menu-field-item-single-mode');
                        this.$multi_mode = this.$menu.find('.ac-game-menu-field-item-multi-mode');
                        this.$settings = this.$menu.find('.ac-game-menu-field-item-settings');

                        this.start();
                    }

                    start() {
                        this.add_listening_events();
                    }

                    add_listening_events() {
                        let outer = this;
                        this.$single_mode.click(function(){
                            outer.hide();
                            outer.root.playground.show();
                        });
                        this.$multi_mode.click(function(){
                            console.log("click multi mode");
                        });
                        this.$settings.click(function(){
                            console.log("click settings");
                            outer.root.settings.logout_on_remote();
                        });
                    }

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

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

        由于之前写的内容都放在了settigns,所以我们需要重新创建一个模块叫settings,
            game/static/js/src/settings/zbase.js,如下:
                class Settings {
                    constructor(root) {
                        this.root = root;
                        this.platform = "WEB"; #默认在web平台
                        if (this.root.AcWingOS) this.platform = "ACAPP"; #判断是什么平台,如果有传入参数,则是acapp平台

                        this.start();
                    }

                    start() {
                        this.getinfo(); //获取用户信息
                    }

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

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

                    getinfo() {
                        let outer = this;
                        //背过
                        $.ajax({
                            url: "https://app3246.acapp.acwing.com.cn/settings/getinfo/",
                            type: "GET",
                            data: {
                                platform: outer.platform,
                            },
                            success: function(resp) { //调用成功的回调函数 resp是getinfo文件中返回的信息字典
                                console.log(resp);
                                if (resp.result === "success") { //如果成功,则隐藏登录界面,打开菜单界面
                                    outer.hide();
                                    outer.root.menu.show();
                                } else { //如果失败,继续弹出登录界面
                                    outer.login();
                                }
                            }
                        });
                    }

                    hide(){

                    }

                    show(){

                    }
                }

            定义之后,一定要继续的在根class下创建该class。

            然后补充一下getinfo:
                if platform == "ACAPP":
                    return getinfo_acapp(request)
                elif platform == "WEB":  //加上判定条件
                    return getinfo_web(request)

            修改js文件之后,重新打包且重启服务,按下F12就可以看到返回的信息,因为当前没有判断是否登录,所以直接默认返回登录成功,接下来我们写一下,判断是否登录:
                在game/views/settings/getinfo.py下:
                    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,
                            'photo': player.photo,
                        })

                    def getinfo_web(request):
                        user = request.user #取得user
                        if not user.is_authenticated: #判断是否没有登录
                            return JsonResponse({ #返回字典
                                'result': "未登录"
                            })
                        else:
                            player = Player.objects.all()[0]
                            return JsonResponse({
                                'result': "success",
                                'username': player.user.username,
                                'photo': player.photo,
                            })

                    def getinfo(request):
                        platform = request.GET.get('platform')
                        if platform == "ACAPP":
                            return getinfo_acapp(request)
                        elif platform == "WEB":
                            return getinfo_web(request)

            打包重启服务后,发现,还是登录状态,是因为后端管理员页面是登录状态,所以前端依然是登录状态,后台退出登录之后,前端就显示未登录了,而在acapp端,仍然无脑返回登录状态,这样就实现了不同平台的不同逻辑

            然后再对settings进行补充:
                ...
                if (this.root.AcWingOS) this.platform = "ACAPP"; //将信息存下来

                this.username = "";
                this.photo = "";
                ...

                ...
                getinfo() {
                    success: function(resp) {
                        console.log(resp);
                        if (resp.result === "success") {
                            outer.username = resp.username;
                            outer.photo = resp.photo;
                            ...
                        } 
                    }
                }
                ...

            然后进入class Players类,画上头像:
                class Player extends AcGameObject {
                    constructor(playground, x, y, radius, color, speed, is_me) {
                        super();
                        ...

                        if (this.is_me) {//判断是否为自己
                            this.img = new Image();
                            this.img.src = this.playground.root.settings.photo;
                        }
                    }


                    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();
                            this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
                            this.ctx.fillStyle = this.color;
                            this.ctx.fill();
                        }
                    }

                    ...

            打包且重启服务,然后就会发现自己操控的圆已经有头像了。如果web端正常,而acapp端运行错误,可能是因为图片有权限,可以尝试换一张图片


4.渲染登录界面:
    先写js
            class Settings {
                constructor(root) {
                    this.root = root;
                    this.platform = "WEB";
                    if (this.root.AcWingOS) this.platform = "ACAPP";
                    this.username = "";
                    this.photo = "";

                    this.$settings = $(`
            <div class="ac-game-settings">
                <div class="ac-game-settings-login">
                    <div class="ac-game-settings-title">
                        登录
                    </div>
                    <div class="ac-game-settings-username">
                        <div class="ac-game-settings-item">
                            <input type="text" placeholder="用户名">
                        </div>
                    </div>
                    <div class="ac-game-settings-password">
                        <div class="ac-game-settings-item">
                            <input type="password" placeholder="密码">
                        </div>
                    </div>
                    <div class="ac-game-settings-submit">
                        <div class="ac-game-settings-item">
                            <button>登录</button>
                        </div>
                    </div>
                    <div class="ac-game-settings-error-message">
                    </div>
                    <div class="ac-game-settings-option">
                        注册
                    </div>,
                    <br> //前两行是共行,可能会影响后面的内容,需要手写换行
                    <div class="ac-game-settings-acwing">
                        <img width="30" src="https://app165.acapp.acwing.com.cn/static/image/settings/acwing_logo.png">
                        <br>
                        <div>
                            AcWing一键登录
                        </div>
                    </div>
                </div>
                <div class="ac-game-settings-register">
                    <div class="ac-game-settings-title">
                        注册
                    </div>
                    <div class="ac-game-settings-username">
                        <div class="ac-game-settings-item">
                            <input type="text" placeholder="用户名">
                        </div>
                    </div>
                    <div class="ac-game-settings-password ac-game-settings-password-first">
                        <div class="ac-game-settings-item">
                            <input type="password" placeholder="密码">
                        </div>
                    </div>
                    <div class="ac-game-settings-password ac-game-settings-password-second">
                        <div class="ac-game-settings-item">
                            <input type="password" placeholder="确认密码">
                        </div>
                    </div>
                    <div class="ac-game-settings-submit">
                        <div class="ac-game-settings-item">
                            <button>注册</button>
                        </div>
                    </div>
                    <div class="ac-game-settings-error-message">
                    </div>
                    <div class="ac-game-settings-option">
                        登录
                    </div>
                    <br>
                    <div class="ac-game-settings-acwing">
                        <img width="30" src="https://app165.acapp.acwing.com.cn/static/image/settings/acwing_logo.png">
                        <br>
                        <div>
                            AcWing一键登录
                        </div>
                    </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_error_message = this.$login.find(".ac-game-settings-error-message");
                    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_password_confirm = this.$register.find(".ac-game-settings-password-second input");
                    this.$register_submit = this.$register.find(".ac-game-settings-submit button");
                    this.$register_error_message = this.$register.find(".ac-game-settings-error-message");
                    this.$register_login = this.$register.find(".ac-game-settings-option");

                    this.$register.hide();都需要先隐藏

                    this.root.$ac_game.append(this.$settings); //将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();
                    });
                }

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

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

                getinfo() {
                    let outer = this;

                    $.ajax({
                        url: "https://app165.acapp.acwing.com.cn/settings/getinfo/",
                        type: "GET",
                        data: {
                            platform: outer.platform,
                        },
                        success: function(resp) {
                            console.log(resp);
                            if (resp.result === "success") {
                                outer.username = resp.username;
                                outer.photo = resp.photo;
                                outer.hide();
                                outer.root.menu.show();
                            } else {
                                outer.login();
                            }
                        }
                    });
                }

                hide() {
                    this.$settings.hide();
                }

                show() {
                    this.$settings.show();
                }
            }

    修改css之前,先下载一下登录界面的图片:
        在/acapp/game/static/image/setting,下载图片,
            wget https://www.shouyihuo.com/uploads/allimg/140917/1136095301-13.gif,
            修改名字
                mv 1136095301-13.gif Dragon_Balls.gif
    再去修改css
        /game/static/css/game.css:
            .ac-game-settings {
                width: 100%;
                height: 100%;
                background-image: url("/static/image/menu/Dragon_Balls.gif");
                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-title {
                color: white;
                font-size: 3vh;
                text-align: center;
                padding-top: 2vh;
                margin-bottom: 2vh;
            }

            .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-acwing {
                display: block;
                height: 7vh;
            }

            .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: white;
                width: 90%;
                line-height: 3vh;
                position: relative;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                background-color: #4CAF50;
                border-radius: 5px;
            }

            .ac-game-settings-error-message {
                color: red;
                font-size: 0.8vh;
                display: inline;
                float: left;
                padding-left: 1vw;
            }

            .ac-game-settings-option {
                color: white;
                font-size: 2vh;
                display: inline;
                float: right;
                padding-right: 1vw;
                cursor: pointer;
            }

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

            .ac-game-settings-acwing > div {
                color: white;
                font-size: 1.5vh;
                text-align: center;
                display: block;
            }

            .ac-game-settings-register {
                height: 49vh;
                width: 20vw;
                position: relative;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                background-color: rgba(0, 0, 0, 0.7);
                border-radius: 5px;
            }

    上面设置一键登录的logo时,需要先将logo下载到服务器:
        /game/static/image/setting,
            wget 图片网址,下载之后,取名acwing_logo.png,然后去浏览器中输入路由看看有没有下载成功

4.写前后端交互:
    老三样 views urls js:
        写views,game/views/settings/login.py:
            from django.http import JsonResponse #用于返回字符串
            from django.contrib.auth import authenticate, login #验证密码是否正确,并且引入login函数

            def signin(request):
                data = request.GET  #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"
                })
        写urls,game/urls/settings/index.py:
            from game.views.settings.login import signin # 引入自己写的逻辑

            urlpatterns = [
                ...
                path("login/", signin, name = "settings_login"), # "settings/login/"
            ]

        写js,game/static/js/src/settings/zbase.js:
        ...
            login_on_remote() {  // 在远程服务器上登录
                let outer = this;
                let username = this.$login_username.val();  //存值
                let password = this.$login_password.val();
                this.$login_error_message.empty();  //清空错误信息

                $.ajax({
                    url: "https://app165.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_error_message.html(resp.result);   //运行失败,显示出来
                        }
                    }
                });
            }
        ...

    同样的方式创建登出,
        写views,game/views/settings/logout.py:
            from django.http import JsonResponse
            from django.contrib.auth import logout


            def signout(request):
                user = request.user
                if not user.is_authenticated:
                    return JsonResponse({
                        'result': "success",
                    })
                logout(request)
                return JsonResponse({
                    'result': "success",
                })
        写urls, game/urls/settings/index.py:
            from game.views.settings.logout import signout


            urlpatterns = [
            ...
            path("logout/", signout, name="settings_logout"),
            ...
            ]

        写js,game/static/js/src/settings/zbase.js:
            logout_on_remote() {  // 在远程服务器上登出
                if (this.platform === "ACAPP") return false;    //acapp端直接返回,因为acapp没有这个服务

                $.ajax({
                    url: "https://app165.acapp.acwing.com.cn/settings/logout/",
                    type: "GET",
                    success: function(resp) {
                        console.log(resp);
                        if (resp.result === "success") {
                            location.reload();
                        }
                    }
                });
            }

        然后借用一下设置按钮,改成退出:
            在game/static/js/src/menu/zbase.js:
                ...
                    <div class="ac-game-menu-field-item ac-game-menu-field-item-settings">
                        退出
                    </div>
                ...
            ...
            this.$settings.click(function(){
                console.log("click settings");
                outer.root.settings.logout_on_remote();
            });
            ...

            然后打包重启服务即可

    同样的方式写注册:
        先写vies,game/views/settings/register.py:
            from django.http import JsonResponse
            from django.contrib.auth import login
            from django.contrib.auth.models import User
            from game.models.player.player import Player

            def register(request):
                data = request.GET
                username = data.get("username", "").strip() //strip()去掉前后空格
                password = data.get("password", "").strip()
                password_confirm = data.get("password_confirm", "").strip()
                if not username or not password:
                    return JsonResponse({
                        'result': "用户名和密码不能为空"
                    })
                if password != password_confirm:
                    return JsonResponse({
                        'result': "两个密码不一致",
                    })
                if User.objects.filter(username=username).exists(): //filter查找数据库
                    return JsonResponse({
                        'result': "用户名已存在"
                    })
                user = User(username=username)
                user.set_password(password)
                user.save()
                Player.objects.create(user=user, photo="https://img2.baidu.com/it/u=2161949891,656888789&fm=26&fmt=auto")
                login(request, user)
                return JsonResponse({
                    'result': "success",
                })

        写路由game/urls/settings/index.py:
            from django.urls import path
            from game.views.settings.getinfo import getinfo
            from game.views.settings.login import signin
            from game.views.settings.logout import signout
            from game.views.settings.register import register


            urlpatterns = [
                path("getinfo/", getinfo, name="settings_getinfo"),
                path("login/", signin, name="settings_login"),
                path("logout/", signout, name="settings_logout"),
                path("register/", register, name="settings_register"),
            ]

        写js,game/static/js/src/settings/zbase.js:
            register_on_remote() {  // 在远程服务器上注册
                let outer = this;
                let username = this.$register_username.val();
                let password = this.$register_password.val();
                let password_confirm = this.$register_password_confirm.val();
                this.$register_error_message.empty();

                $.ajax({
                    url: "https://app165.acapp.acwing.com.cn/settings/register/",
                    type: "GET",
                    data: {
                        username: username,
                        password: password,
                        password_confirm: password_confirm,
                    },
                    success: function(resp) {
                        console.log(resp);
                        if (resp.result === "success") {
                            location.reload();  // 刷新页面
                        } else {
                            outer.$register_error_message.html(resp.result);
                        }
                    }
                });
            }

        到这里,就完成了注册登录页面。

作者:樱桃小完犊子_1
链接:https://www.acwing.com/activity/content/code/content/4344196/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胤凯o

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值