Django project notes - (implementation of user system)

Posted by Sir Mildred Pierce on Thu, 10 Feb 2022 01:15:08 +0100

Django class notes (IV) - (implementation of user system)

For the process of docking acapp in the last class, since it does not involve intellectual content, we will not write a separate blog. For the content of docking acapp and assigning domain names, please refer to:

Deploy nginx and docking acapp - AcWing

You are also welcome to visit other blogs of my project class:

Django class notes (I) - environment configuration and project creation (the process is very detailed) - AcWing

(updated version) Django class notes (II) - Implementation of menu module, including script for automatically creating projects

pycharm connects to the server and writes code synchronously (detailed graphic process)

linux basic course thrift detailed development process - AcWing

Project address

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

preparation

1. In order to enable the error message to be displayed on the browser during debugging, you need to change DEBUG = False to DEBUG = True in acapp/acapp/settings

2. In order to view the background data management system, you need to create a super account (as mentioned earlier). The creation command is:

#It needs to be executed under the root directory of the project, acapp
python3 manage.py createsuperuser 

3. Way to enter the background: after your domain name + / admin

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

Extended database

background knowledge

1. The default data relationship in Django uses sqlite3,

  • It is a lightweight database and abides by ACID (atomicity, consistency, isolation and persistence) relational database management system
  • Zero configuration - no need to install and manage configuration
  • A complete database stored in a single disk file
  • Support database size 2TB, small enough, about 130000 lines of C code, 4.43M, faster than some popular databases in most databases
  • Independence: no additional dependencies
  • The source code is completely open source. You can use it in any way, and you can sell it
  • Support multiple development languages, such as C,C++,C#,PHP,Perl,Java,Python,Ruby, etc
  • Well annotated source code, with more than 90% test coverage, and supports a variety of SQL statements

2.django can also support other databases.

In the actual development scenario, as general y said in class, the database is generally placed on another server dedicated to storing the database. For our current lightweight thinking, we don't need to consider using mysql as the database. Just use the default database.

3. For Django's method of changing to other databases, please refer to:

django using MySQL database - Liu Jiang's django tutorial (liujiangblog.com)

Django's detailed models operation - Wangwang xiaomiaomi - blog Garden (cnblogs.com)

4. The database management module of Django is models Py. If the logic is complex, change this file into the models folder and create a folder in it__ init__.py file

Add custom data table

Because there may be many tables for account information, folders are used for management

Every time you replace a file with a folder, create a folder under the folder__ init__.py file

Create table player

Create a file player under game/models and a file player under player Py stores the information of the player table

player.py contents are as follows:

#Inherit the base class of django database
from django.db import models
from django.contrib.auth.models import User

#The inherited classes are written in parentheses
class Player(models.Model):
    #Define the association relationship, and each player corresponds to a user
    #When the user is deleted, the corresponding player is also deleted
    user = models.OneToOneField(User,on_delete=models.CASCADE)
    photo = models.URLField(max_length=256,blank=True)

    #Displays the name of each player's data in the background
    def __str__(self):
        return str(self.user)

Register the player table in the background management interface

1. Change game / Admin py:

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

admin.site.register(Player)

2. Run two commands to update the database table in the background

python3 manage.py makemigrations
python3 manage.py migrate

3. Note:

Nginx itself is a static resource server. When there are only static resources, you can use nginx as the server.

Therefore, when static resources are updated, the client will also update synchronously; However, when the background resources are updated, the client will not update synchronously. You need to restart the ngnix service to update.

Start ngnix:

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

Establishment of user system

1. In order to support multi terminal operation, you need to pass in parameters in AcGame class to support and judge different terminals

2. Every time you write a function (the task of front and rear end interaction), you need to implement:

  • The views layer implements the logic of calling the database
  • Implement routing in url layer
  • js to call the back-end return parameters

Logic diagram:

Implement the view layer

In terms of business, we put the user setting menu of view layer and the logic of user related operations in the folder of game/views/settings, and the operations related to user login in the folder of game/views/settings / getinfo Py:

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


#Request function on the acapp side
def getinfo_acapp(request):
    #The first data in the table
    player = Player.objects.all()[0]
    return JsonResponse({
        'result': "success",
        'username': player.user.username,
        'photo': player.photo,
    })


#Request function on the web side
def getinfo_web(request):
    user = request.user
    if not user.is_authenticated:
        return JsonResponse({
            'result': "Not logged in"
        })
    else:
        player = Player.objects.all()[0]
        return JsonResponse({
            'result': "success",
            'username': player.user.username,
            'photo': player.photo,
        })


#Classify and process requests from different ends
def getinfo(request):
    #Get a parameter from the front end through the get request
    platform = request.GET.get('platform')
    #Judge which end sent the request
    if platform == "ACAPP":
        return getinfo_acapp(request)
    elif platform == "WEB":
        return getinfo_web(request)
    else:
        return JsonResponse({
            'result': "other"
        })

Implement url layer

/ settings / game.urls Py, the functions in the view layer just implemented are introduced:

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


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

]

Implement js

Modify game / static / JS / SRC / menu / zbase js:

Since the code here is too long, it will not be displayed here. Please move to:

Access process of the whole user system

Please refer to my other detailed blog

Implementation of user registration and login system

Note: when performing multi terminal operation, the login status of the web terminal is synchronized with that of the background. If you want to debug, you must pay attention to logging out of the background account

js layer

Because it is too lengthy and non key, you can query the source code of html and css

Logical implementation of front-end information sending and receiving

  1. Get the information filled in by the user from the web page form. Pull out the elements of the corresponding form in the dom tree and save them in the constructor()
  2. Function to send information to the back end after mouse click

In game / static / SRC / menu / settings / zbase js

class Settings {
    constructor(root) {
        this.root = root;
        //Parameter indicating which end
        this.platform = "WEB";
        if (this.root.AcWingOS) this.platform = "ACAPP";
        //Receive backend parameters
        this.username = "";
        this.photo = "";

        this.$settings = $(`
            <div class="ac-game-settings">
    <div class="ac-game-settings-login">
        <div class="ac-game-settings-title">
            Sign in
        </div>
        <div class="ac-game-settings-username">
            <div class="ac-game-settings-item">
                <input type="text" placeholder="user name">
            </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">
                <input type="button" value="Sign in">
            </div>
        </div>
        <div class="ac-game-settings-error-message">
        </div>
        <div class="ac-game-settings-option">
            register
        </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 One click login
                </div>
            </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="user name">
            </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">
                <input type="button" value="register">
            </div>
        </div>
        <div class="ac-game-settings-error-message">
        </div>
        <div class="ac-game-settings-option">
            Sign in
        </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 One click login
                </div>
            </div>
            <br>

        </div>
    </div>
</div>
        `);
        //Load the login interface into the DOM tree
        // this.root.$ac_game.append(this.$settings);
        //Find the login window node and its subtree
        this.$login = this.$settings.find(".ac-game-settings-login");
        //Locate the user name entry form for the login window
        this.$login_username = this.$login.find(".ac-game-settings-username input");
        //Locate the enter password form for the login window
        this.$login_password = this.$login.find(".ac-game-settings-password input");
        //Locate the login button in the login window
        this.$login_submit = this.$login.find(".ac-game-settings-submit>div>input");
        //Display error message
        this.$login_error_message = this.$login.find(".ac-game-settings-error-message");
        Locate the register button in the login window
        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();
    }

    /**
     * The function that executes when the object is created
     */
    start() {
        this.getinfo();
        this.add_listening_events();
    }

    /**
     * Function to get back-end information
     */
    getinfo() {
        let outer = this;

        $.ajax({
            url: "https://app220.acapp.acwing.com.cn/settings/getinfo/",
            type: "GET",
            data: {
                platform: outer.platform,
            },
            //Function executed after getting back-end parameters
            success: function (resp) {
                console.log(resp);
                if (resp.result === "success") {
                    outer.username = resp.username;
                    outer.photo = resp.photo;
                    //Login interface hidden
                    outer.hide();
                    //Display menu interface
                    outer.root.menu.show();
                } else {
                    //If the information acquisition fails (i.e. the user is not logged in), the login interface will continue to be displayed
                    outer.open_login();
                }
            }
        });
    }

    /**
     * Open login interface
     */
    open_login() {
        this.$register.hide();
        this.$login.show();
    }

    /**
     * Open the registration interface
     */
    open_register() {
        this.$login.hide();
        this.$register.show();
    }

    /**
     * Hide registration / login interface
     */
    hide() {
        this.$settings.hide();
    }

    /**
     * Display the registration / login interface
     */
    show() {
        this.$settings.show();
    }

    /**
     * Function triggered after mouse click
     */
    add_listening_events() {
        this.add_listening_events_login();
        this.add_listening_events_register();
    }

    /**
     * Function triggered after clicking the login button
     */
    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();
        });
    }

    /**
     * Function triggered after clicking the register button
     */
    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();
        });
    }

    /**
     * Send the filled account and password to the back end, verify and return the information
     */
    login_on_remote() {  // Log on to the remote server
        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);
                }
            }
        });
    }

    /**
     * Registered user
     */
    register_on_remote() {  // Register on remote server
        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();  // Refresh page
                } else {
                    outer.$register_error_message.html(resp.result);
                }
            }
        });
    }

    /**
     * Log out on remote server
     * @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 layer

background knowledge

Django user authentication (Auth) component | rookie tutorial (runoob.com)

Blog - authentico.com

realization

Sign in

Create login under game/views/settings 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': "Username or password incorrect "
        })
    login(request, user)
    return JsonResponse({
        'result': "success"
    })

Log out

Create logout under game/views/settings 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',
    })
register

Create register under game/views/settings 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': "User name and password cannot be empty"
        })
    if password != password_confirm:
        return JsonResponse({
            'result': "The two passwords are inconsistent",
        })
    if User.objects.filter(username=username).exists():
        return JsonResponse({
            'result': "User name already exists"
        })
    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': "User name and password cannot be empty"
        })
    if password != password_confirm:
        return JsonResponse({
            'result': "The two passwords are inconsistent",
        })
    if User.objects.filter(username=username).exists():
        return JsonResponse({
            'result': "User name already exists"
        })
    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 layer

/ settings / game.urls Py adds the functions implemented by the view layer to the routing

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


Implementation of one click login on Acwingweb

preparation:

What is redis

Redis is a high-performance key value database.

Configure Redis

  1. Install django_redis
pip install django_redis
  1. Configure settings py
    Baidu has been here for a long time, basically copying and pasting
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. Start redis server
sudo redis-server /etc/redis/redis.conf

django background operation redis

1. Open the django interactive background of the project

python3 manage.py shell

2. Import cache layer related packages

from django.core.cache import cache

3. Some commands for redis operation

List all key s in rediscache.keys('*')cache. The expressions in keys () support regular expressions
Insert a piece of data into rediscache.set(key,value,passtime)
Query whether a key existscache.has_key('')

Idea:

  1. After one click login, the front end sends a fixed format request to acwing
  2. Jump to the authorization interface

Sprinkle flowers at the end~

Topics: Python Django Back-end