Django项目笔记(四)——(用户系统的实现)

Django上课笔记(四)——(用户系统的实现)

对于上节课对接acapp的过程由于不涉及知识性的内容,就不单独写一篇博客了。对接acapp及分配域名的内容请参考:

部署nginx与对接acapp - AcWing

也欢迎大家光临我另外项目课的其他博客:

Django上课笔记(一)——环境配置与项目创建(过程十分详细) - AcWing

(更新版)Django上课笔记(二)——菜单模块的实现, 含自动创建项目的脚本

pycharm连接服务器同步写代码(图文详细过程)

linux基础课thrift详细开发过程 - AcWing

项目地址

https://git.acwing.com/codeRokie/acapp

准备工作

1.为了在调试时能让报错信息能显示在浏览器上,需要在acapp/acapp/settings中将DEBUG = False改为DEBUG = True

2.为了查看后台数据管理系统,需要创建超级账户(之前讲过),创建的命令为:

#需要在项目的根目录acapp下执行
python3 manage.py createsuperuser 

3.进入后台的方式:你的域名后+/admin

docker run -p 20000:22 -p 8000:8000 -p 8001:80 -p 8002:443 --name acgame -itd django_lesson:2

扩充数据库

背景知识

1.django中默认的数据关系使用的的是sqlite3,
  • 他是一款轻型的数据库,遵守了ACID(原子性,一致性,隔离性,持久性)的关系型数据库管理系统
  • 零配置-无需安装和管理配置
  • 储存在单一磁盘文件中的一个完整的数据库
  • 支持数据库大小志2TB足够小,大概13万行C代码,4.43M,比一些流行的数据库在大部分数据库操作要快
  • 独立:没有额外的依赖
  • 源码完全的开源,你可以用于任何途径,你也可以出售他
  • 支持多种开发语言,C,C++,C#,PHP,Perl,Java,Python,Ruby等
  • 良好注释的源代码, 并且有着90%以上的测试覆盖率,且支持多种SQL语句
2.django当然也可以支持其他的数据库。

在实际的开发场景中,如y总课上所说,数据库一般是放在另一台专门存储数据库的服务器上的。对于我们现在这种轻量级想,则不用考虑用mysql作为数据库。直接用他默认给的数据库就可以。

3.django换用其他数据库的方法,请参考:

django 使用MySQL数据库 - 刘江的django教程 (liujiangblog.com)

Django详解之models操作 - 汪汪小喵咪 - 博客园 (cnblogs.com)

4.django的数据库管理模块是models.py,如果逻辑复杂就把这个文件变为models文件夹,并在里面创建一个__init__.py文件

添加自定义的数据表

因为账号信息可能有很多表,所以用文件夹进行管理

每用一个文件夹代替一个文件,都要在文件夹下创建一个__init__.py文件

创建表player

game/models下创建文件player,在player下创建一个文件player.py存储player表的信息

player.py内容如下:

#继承django数据库的基类
from django.db import models
from django.contrib.auth.models import User

#继承的类写在括号中
class Player(models.Model):
    #定义关联关系,每个player对应一个user
    #当user被删除,对应的player也被删除
    user = models.OneToOneField(User,on_delete=models.CASCADE)
    photo = models.URLField(max_length=256,blank=True)

    #显示每个player的数据在后台的名字
    def __str__(self):
        return str(self.user)

将player表注册到后台管理界面中

1.改动game/admin.py:

from django.contrib import admin
from game.models.player.player import Player
# Register your models here.

admin.site.register(Player)

2.运行2个命令,使后台更新数据库表

python3 manage.py makemigrations
python3 manage.py migrate

3.注意:

Nginx本身是一个静态资源的服务器,当只有静态资源的时候,就可以使用Nginx来做服务器。

所以当静态资源更新时,客户端也会同步更新;但当后台资源更新时,客户端不会同步更新,需要重启ngnix服务,才能更新。

启动ngnix:

sudo /etc/init.d/nginx start
uwsgi --ini scripts/uwsgi.ini 

用户系统的建立

1.为了支持多端操作,需要在AcGame类中传入参数,用来支持和判断不同的端

2.每写一个函数(前后端交互的任务)的时候需要实现:

  • views层实现调用数据库的逻辑
  • url层中实现路由
  • js中实现对后端返回参数的调用

逻辑图:

实现view

在业务上,我们把视图层用户设置菜单与用户相关操作的逻辑放在game/views/settings文件夹下,与用户登录相关的操作,放在game/views/settings/getinfo.py中:

from django.http import JsonResponse
from game.models.player.player import Player


#在acapp端的请求函数
def getinfo_acapp(request):
    #表中的第一条数据
    player = Player.objects.all()[0]
    return JsonResponse({
        'result': "success",
        'username': player.user.username,
        'photo': player.photo,
    })


#在web端的请求函数
def getinfo_web(request):
    user = request.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):
    #通过get请求从前端获取一个参数
    platform = request.GET.get('platform')
    #判断是哪个端发来的请求
    if platform == "ACAPP":
        return getinfo_acapp(request)
    elif platform == "WEB":
        return getinfo_web(request)
    else:
        return JsonResponse({
            'result': "其他"
        })

实现url

game/urls/settings/index.py中,引入刚才实现的view层中的函数:

from django.urls import path
from game.views.settings.getinfo import getinfo


urlpatterns = [
    path("getinfo/", getinfo, name="settings_getinfo"),

]

实现js

修改game/static/js/src/menu/zbase.js:

这里由于代码过长,就不在此展示,请移步:

整个用户系统的访问流程

请参考我的另一篇详细博客

用户注册登录系统的实现

注意:在执行多端操作的时候,web端的登录状态和后台的登录状态同步,如果要调试,一定要注意登出后台账号

js

由于过于冗长且非重点,htmlcss部分大家可以自行查询源码

前端信息发送和接收的逻辑实现
  1. 从网页表单中获取用户填入的信息。在dom树中将对应表单的元素"抠"出来,保存在constructor()
  2. 实现鼠标点击后向后端发送信息的函数

game/static/src/menu/settings/zbase.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">
                <input type="button" value="登录">
            </div>
        </div>
        <div class="ac-game-settings-error-message">
        </div>
        <div class="ac-game-settings-option">
            注册
        </div>
        <br>
        <div class="ac-game-settings-quick-login">
            <div class="ac-game-settings-quick-login-acwing">
                <img width="30" src="https://app165.acapp.acwing.com.cn/static/image/settings/acwing_logo.png">
                <br>
                <div>
                    AcWing一键登录
                </div>
            </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">
                <input type="button" value="注册">
            </div>
        </div>
        <div class="ac-game-settings-error-message">
        </div>
        <div class="ac-game-settings-option">
            登录
        </div>
        <br>
        <div class="ac-game-settings-quick-login">
            <div class="ac-game-settings-quick-login-acwing">
                <img width="30" src="https://app165.acapp.acwing.com.cn/static/image/settings/acwing_logo.png" >
                <div>
                    AcWing一键登录
                </div>
            </div>
            <br>

        </div>
    </div>
</div>
        `);
        //把登录界面加载到DOM树中
        // this.root.$ac_game.append(this.$settings);
        //找到登录窗口节点及其子树
        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>div>input");
        //显示错误信息
        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>div>input");
        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);

        this.start();
    }

    /**
     * 在对象创建时执行的函数
     */
    start() {
        this.getinfo();
        this.add_listening_events();
    }

    /**
     * 获得后端信息的函数
     */
    getinfo() {
        let outer = this;

        $.ajax({
            url: "https://app220.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.open_login();
                }
            }
        });
    }

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

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

    /**
     * 隐藏注册/登录界面
     */
    hide() {
        this.$settings.hide();
    }

    /**
     * 显示注册/登录界面
     */
    show() {
        this.$settings.show();
    }

    /**
     * 鼠标点击后触发的函数
     */
    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 () {
            console.log("666")
            outer.open_register();
        });
        this.$login_submit.click(function () {
            outer.login_on_remote();
        });
    }

    /**
     * 点击注册按钮后触发的函数
     */
    add_listening_events_register() {
        let outer = this;
        this.$register_login.click(function () {
            console.log('666')
            outer.open_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_error_message.empty();

        $.ajax({
            url: "https://app220.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);
                }
            }
        });
    }

    /**
     * 注册用户
     */
    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://app220.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);
                }
            }
        });
    }

    /**
     * 在远程服务器上登出
     * @returns {boolean}
     */
    logout_on_remote() {
        if (this.platform === "ACAPP") return false;

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

view

背景知识

Django 用户认证(Auth)组件 | 菜鸟教程 (runoob.com)

Django中authenticate和login模块 - ccorz - 博客园 (cnblogs.com)

实现
登录

game/views/settings下创建login.py

from django.http import JsonResponse

from django.contrib.auth import authenticate, login


def signin(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/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',
    })
注册

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()
    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():
        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",
    })
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()
    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():
        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",
    })

urls

game/urls/settings/index.py中把view层实现的函数加进路由中

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"),
]


Acwingweb端一键登录实现

准备工作:

什么是redis

Redis 是一个高性能的key-value数据库。

配置Redis
  1. 安装django_redis
pip install django_redis
  1. 配置settings.py
    这里百度了好久,基本上都是复制粘贴
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'
  1. 启动redis-server
sudo redis-server /etc/redis/redis.conf
django后台操作redis

1.打开项目的django交互式后台

python3 manage.py shell

2.导入cache层相关的包

from django.core.cache import cache

3.操作redis的一些命令

列出redis中的所有keycache.keys(’*’)cache.keys()中的表达式支持正则
向redis中插入一条数据cache.set(key,value,passtime)
查询某个key是否存在cache.has_key(’’)

思路:

  1. 前端点击一键登录后,向acwing发送一个固定格式的请求
  2. 跳转至授权界面

完结撒花~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值