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:
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
- 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()
- 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)
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
- Install django_redis
pip install django_redis
- 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'
- 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 redis | cache.keys('*') | cache. The expressions in keys () support regular expressions |
Insert a piece of data into redis | cache.set(key,value,passtime) | |
Query whether a key exists | cache.has_key('') |
Idea:
- After one click login, the front end sends a fixed format request to acwing
- Jump to the authorization interface
Sprinkle flowers at the end~