- Cấu trúc thư mục dự án Luffy ===============
# Tạo dự án, cần chọn môi trường ảo để tạo
# Trước khi tạo dự án Luffy bằng môi trường ảo, phải cài đặt django trước, không sẽ dùng django đầu tiên có sẵn
# Hoặc sử dụng django-admin để tạo
# Nếu đã có dự án, trước tiên chuyển đổi trình thông dịch, sau đó chuyển trong pycharm
# Điều chỉnh cấu trúc thư mục dự án Luffy
├── luffyapi
├── logs/ # Thư mục nhật ký khi chạy dự án/phát triển - gói
├── manage.py # Tập lệnh
├── luffyapi/ # Ứng dụng chính dự án, lưu mã nguồn khi phát triển - gói
├── apps/ # Thư mục lưu mã nguồn nhà phát triển, lưu theo mô-đun [ứng dụng con] - gói
├── libs/ # Thư mục lưu thư viện bên thứ ba [thành phần, mô-đun bên thứ ba] - gói
├── settings/ # Thư mục cấu hình - gói
├── dev.py # Cấu hình cục bộ khi phát triển dự án
└── prod.py # Cấu hình khi dự án triển khai
├── urls.py # Tổng tuyến đường
└── utils/ # Thư viện hàm công cộng cho nhiều mô-đun [ứng dụng con] [thành phần tự phát triển]
└── scripts/ # Lưu tập lệnh khi vận hành dự án - thư mục
# Để chạy, sửa dòng 9 trong manage.py
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffy_api.settings.dev')
# Để triển khai (sửa sau khi triển khai)
wsgi.py dòng 14
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffy_api.settings.prod')
# Khi tạo app, phải thực thi trong thư mục apps
python ../../manage.py startapp home
# Đăng ký app
- Khi nhập gói, luôn bắt đầu từ biến môi trường
# Thêm vào settings/dev.py
import sys
import os
BASE_DIR = Path(__file__).resolve().parent.parent #luffy_api nhỏ
# Thêm đường dẫn của luffy_api nhỏ và apps vào biến môi trường. Sau này có thể nhập trực tiếp từ các đường dẫn này
sys.path.append(str(BASE_DIR))
sys.path.append(os.path.join(BASE_DIR,'apps'))
# Sau này khi đăng ký app, chỉ cần viết tên app
- Cấu hình hệ thống Luffy: Đóng gói ============
Đóng gói trình ghi nhật ký
# Mỗi dự án, đều cần ghi nhật ký
- Sau này có thể sử dụng nhật ký để gỡ lỗi, phân tích lỗi
- Phân tích hành vi người dùng...
# Trước đây đã học về mô-đun logging, django dựa trên mô-đun logging gốc
# Tích hợp nhật ký vào dự án, làm như thế nào
- Sao chép mã, đặt vào tệp cấu hình
- Thứ hai: tạo common_logger.py trong utils
import logging
# Lấy đối tượng logger theo tên trong tệp cấu hình, sau này chỉ cần nhập và sử dụng đối tượng để ghi nhật ký
logger=logging.getLogger('django')
- Bước thứ ba: Ở nơi muốn sử dụng, nhập (lưu ý đường dẫn), sử dụng logger.info trực tiếp...
Đóng gói ngoại lệ toàn cục
# DRF đã xử lý ngoại lệ toàn cục, chỉ cần viết một hàm, cấu hình trong tệp cấu hình, khi có ngoại lệ, hàm này sẽ thực thi
# Viết một hàm để đóng gói ngoại lệ toàn cục
-1 Định dạng trả về thống nhất
-2 Ghi nhật ký: Khi có ngoại lệ, chương trình có vấn đề, sau này gỡ lỗi
# Các bước sử dụng
1 Tạo một exceptions.py mới
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework.response import Response
from utils.common_logger import logger
def exception_handler(exc, context):
# Khi chương trình có lỗi, sẽ đến đây, chúng ta đều cần ghi nhật ký
# Địa chỉ yêu cầu, phương thức yêu cầu, thời gian yêu cầu, hàm view được yêu cầu, nếu đã đăng nhập, ghi lại id người dùng
request = context.get('request')
try:
user_id = request.user.pk
if not user_id:
user_id = 'Người dùng ẩn danh'
except:
user_id = 'Người dùng ẩn danh'
view = context.get('view')
logger.error('Người dùng:【%s】, sử dụng:【%s】 yêu cầu, yêu cầu:【%s】 địa chỉ, hàm view là:【%s】, đã lỗi, lỗi là:【%s】' % (
user_id, request.method, request.get_full_path(), str(view), str(exc)
))
# Bước đầu tiên: Thực thi ngoại lệ xử lý ban đầu: Nó chỉ xử lý ngoại lệ của drf, không xử lý ngoại lệ của django
# res có giá trị là đối tượng Response, cho biết là ngoại lệ của drf
# res là None, cho biết là ngoại lệ của django
res = drf_exception_handler(exc, context)
# Ở đây, có thể chia ngoại lệ chi tiết hơn qua mã trạng thái: ví dụ có ngoại lệ dữ liệu, ngoại lệ chia cho 0, ngoại lệ vượt quá phạm vi danh sách.....
if res:
# Ngoại lệ drf
# res=Response(data={'code':999,'msg':'Lỗi máy chủ, vui lòng liên hệ quản trị viên hệ thống'})
res = Response(data={'code': 999, 'msg': res.data.get('detail', 'Lỗi máy chủ, vui lòng liên hệ quản trị viên hệ thống')})
else:
# Ngoại lệ django, mã trạng thái là 888, thông báo lỗi là exc đối tượng ngoại lệ chuyển thành chuỗi
res = Response(data={'code': 888, 'msg': str(exc)})
return res
# Cấu hình trong tệp cấu hình
REST_FRAMEWORK = {
# Sau này, chỉ cần có ngoại lệ, sẽ thực thi exception_handler
'EXCEPTION_HANDLER': 'utils.exceptions.exception_handler',
}
Đóng gói response lần thứ hai
# Đối tượng Response được cung cấp bởi drf không dễ dàng thêm các trường code và msg, hãy tự đóng gói một lớp Response, sau này đều sử dụng của chúng ta, thuận tiện hơn khi viết code và msg
# Các bước đóng gói:
1 Trong utils/response.py
from rest_framework.response import Response
class APIResponse(Response):
def __init__(self, code=100, msg='Thành công', status=None, headers=None, **kwargs):
data = {'code': code, 'msg': msg}
if kwargs:
data.update(kwargs)
super().__init__(data=data, status=status, headers=headers)
2 Sau này trong lớp view, nhập và sử dụng
return APIResponse(token='asfdasfd')
return APIResponse(token='asfdasfd',status=201,code=101)
- Cấu hình cơ sở dữ liệu Luffy =========
# Sử dụng mysql cho cơ sở dữ liệu, cấu hình mysql
# Trước đây sử dụng người dùng root làm người dùng cơ sở dữ liệu dự án, quyền quá cao, thông thường trong công ty, sẽ tạo một người dùng riêng cho dự án, người dùng này chỉ có quyền với cơ sở dữ liệu hiện tại
# Trong mysql, tạo một người dùng luffy_api, cấp cho người dùng này tất cả quyền với cơ sở dữ liệu luffy
-1 Kết nối mysql, tạo một cơ sở dữ liệu luffy
- Tạo bằng dòng lệnh
- Tạo bằng client navicate
-2 Xem có những người dùng nào
select user,host from mysql.user;
-3 Tạo một người dùng luffy_api (trước có một người dùng root, quyền rất cao)
# Lệnh cấp quyền: grant quyền(create, update) on cơ_sở_dữ_liu.bảng to 'tài_khoản'@'host' identified by 'mật_khẩu'
# Cấp tất cả quyền cho các bảng trong cơ sở dữ liệu luffy cho người dùng luffy_api, cho phép kết nối từ xa
grant all privileges on luffy.* to 'bxf'@'%' identified by 'bxf123?';
# Cấp tất cả quyền cho các bảng trong cơ sở dữ liệu luffy cho người dùng luffy_api, cho phép kết nối cục bộ
grant all privileges on luffy.* to 'bxf'@'localhost' identified by 'bxf123?';
-4 Đăng nhập với người dùng luffy_api, xem, chỉ có thể thấy cơ sở dữ liệu luffy
# Cấu hình trong dự án để sử dụng mysql
1 Trong cấu hình:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'luffy',
'USER': user,
'PASSWORD': password,
'HOST': '127.0.0.1',
'PORT': 3306
}
}
2 Chạy dự án sẽ báo lỗi, django mặc định sử dụng mysqlDB để thao tác mysql, mô-đun này có thể dùng được trong python2, không hỗ trợ trong python3, vì vậy chúng ta sử dụng pymysql để thay thế, đến django2.0.7 trở đi, nếu sử dụng pymysql để thay thế, cần sửa mã nguồn django, sau này sử dụng mysqlclient để thay thế pymysql, mysqlclient là phiên bản python3.x của mysqlDB
- Nếu sử dụng pymysql, cần sửa mã nguồn, cần thực thi
import pymysql
pymysql.install_as_MySQLdb() # Monkey patch, thay thế tất cả đối tượng mysqlDB thành pymysql
- Monkey patch là: kỹ thuật thay thế động trong quá trình chạy chương trình:https://www.liuqingzheng.top/python/Python%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/24-%E5%8D%8F%E7%A8%8B%E4%B9%8Bgevent%E6%A8%A1%E5%9D%97/
- Sau này trong django không sử dụng pymysql nữa, sử dụng mysqlclient, không cần thực thi bất kỳ patch nào
- Win, linux, mac, mô-đun này không dễ cài, tùy vận, đôi khi rất thuận lợi, đôi khi không cài được
3 Chỉ cần cài mysqlclient, mọi vấn đề đều được giải quyết
# Hiện tại trong tệp cấu hình, viết cứng tên người dùng và mật khẩu mysql
- Có thể rủi ro--- > Nếu mã nguồn của tôi bị rò rỉ--- > Tên người dùng và mật khẩu cơ sở dữ liệu bị rò rỉ--- > Kẻ tấn công có thể đăng nhập từ xa--- > Mất dữ liệu
- Thông tin khách sạn của Hozton bị rò rỉ, mã nguồn bị rò rỉ, dẫn đến mất dữ liệu
- Dữ liệu của Thượng随身办 bị rò rỉ
# Bổ sung:
Sự khác biệt giữa mã utf8 và utf8mb4 của mysql?
-utf8: Một ký tự, chiếm 2 byte (byte--->1 byte là 8 bit 10101010)
-utf8mb4: Một ký tự, chiếm 4 byte, biểu tượng cảm xúc
- utf-8 chúng ta học: có thể thay đổi chiều dài từ 1---4 byte để biểu thị một ký tự<br></br>
- Cấu hình bảng User, mở truy cập media ==========================
# Cấu hình xong mysql, bảng người dùng của dự án là, sẽ sử dụng bảng User của Auth, mở rộng trường
# Các bước sử dụng
-1 Tạo một ứng dụng user: python ../../manage.py startapp user
-2 Trong models.py của app user, mở rộng bảng người dùng
class UserInfo(AbstractUser):
mobile = models.CharField(max_length=11, unique=True)
# Cần hỗ trợ của gói pillow ImageField kế thừa FileField chỉ lưu trữ hình ảnh
icon = models.ImageField(upload_to='icon', default='icon/default.png')
class Meta:
db_table = 'luffy_user' # Chỉ tên bảng
verbose_name = 'Bảng người dùng' # Hiển thị tiếng Trung trong quản trị
verbose_name_plural = verbose_name
def __str__(self):
return self.username
-3 Cấu hình trong tệp cấu hình, đăng ký app, cài đặt gói pillow
# Cấu hình bảng người dùng
AUTH_USER_MODEL='user.UserInfo'
-4 Hai lệnh di chuyển, cần đến đường dẫn BASE_DIR
python manage.py makemigrations
python manage.py migrate
Mở truy cập media
# Các bước
1 Cấu hình trong tệp cấu hình
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
2 Tạo thư mục media, thư mục icon, đặt một hình ảnh vào
3 Thêm vào tuyến đường:
path('media/<path:path>', serve, kwargs={'document_root': settings.MEDIA_ROOT}),
- Tạo và cấu hình dự án giao diện Luffy =============
# 1 Tạo dự án
# 2 Xóa một số không cần thiết
- Trong App.vue chỉ giữ lại
<template>
<div id="app">
<router-view/>
</div>
</template>
# 3 HomeView.vue
<template>
<div class="home">
<h1>Trang chủ</h1>
</div>
</template>
<script>
export default {
name: 'HomeView',
}
</script>
# 4 router/index.js
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
]
Cài đặt axios
# 1 Cài đặt
cnpm install axios
# 2 Cấu hình trong main.js
import axios from 'axios'
Vue.prototype.$axios=axios
# 3 Sau này trong bất kỳ thành phần nào sử dụng
this.$axios.get()
elementui
# Vue2 sử dụng elementui
- Cài đặt: cnpm i element-ui -S
- Cấu hình: trong main.js
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
- Sử dụng: Trong bất kỳ thành phần nào sao chép và dán (template, script, style)
#Vue3 sử dụng element-plus
bootstrap, jquery
# Dự án của chúng ta không sử dụng, nhưng có thể đưa vào sau này
# bootstrap dựa trên jquery
# Các bước sử dụng:
1 Cài đặt
cnpm install jquery -S
cnpm install bootstrap@3 -S
2 Cấu hình: main.js
import 'bootstrap'
import 'bootstrap/dist/css/bootstrap.min.css'
3 Cấu hình vue.config.js
const webpack = require("webpack");
module.exports = {
configureWebpack: {
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery",
"window.$": "jquery",
Popper: ["popper.js", "default"]
})
]
}
};
vue-cookies
# 1 Cài đặt
cnpm install vue-cookies -S
# 2 Cấu hình: trong main.js
import cookies from 'vue-cookies'
Vue.prototype.$cookies=cookies
# 3 Sử dụng: Trong bất kỳ thành phần nào
this.$cookies.set()
- Cấu hình kiểu dáng và JS toàn cục giao diện ==============
# Loại bỏ kiểu mặc định của body div, thống nhất
# Viết một, áp dụng vào dự án
# Địa chỉ giao diện backend, viết thống nhất, sau này thay đổi chung
1.1 global.css
/* Khai báo kiểu toàn cục và kiểu khởi tạo của dự án */
body, h1, h2, h3, h4, h5, h6, p, table, tr, td, ul, li, a, form, input, select, option, textarea {
margin: 0;
padding: 0;
font-size: 15px;
}
a {
text-decoration: none;
color: #333;
}
ul {
list-style: none;
}
table {
border-collapse: collapse; /* Hợp nhất viền */
}
1.2 settings.js
export default {
BASE_URL:'http://127.0.0.1:8000/'
}
1.3 main.js
//5 Loại bỏ kiểu mặc định của tất cả thẻ
import '@/assets/css/global.css'
// 6 Cấu hình toàn cục
import settings from "@/assets/js/settings";
Vue.prototype.$settings=settings
- Giải thích chi tiết vấn đề cross-domain, kết nối frontend-backend (quan trọng) ===================
# Tương tác frontend-backend sẽ có vấn đề cross-domain
# Nguyên nhân gây ra vấn đề cross-domain?
-Chính sách cùng nguồn (Same origin policy) là một thỏa thuận, đây là tính năng cốt lõi và cơ bản nhất của trình duyệt, nếu thiếu chính sách cùng nguồn, chức năng bình thường của trình duyệt có thể bị ảnh hưởng. Có thể nói Web được xây dựng dựa trên chính sách cùng nguồn, trình duyệt chỉ là một cách thực hiện chính sách cùng nguồn.
Địa chỉ url yêu cầu, phải cùng miền với url trên trình duyệt, tức là tên miền, cổng, giao thức phải giống nhau.
Ví dụ: Trên máy tính của tôi tên miền là 127.0.0.1:8000, yêu cầu dữ liệu từ một tên miền khác: 127.0.0.1:8001
Trình duyệt sẽ báo lỗi, đây là sự bảo vệ của chính sách cùng nguồn, nếu trình duyệt không có sự bảo vệ của chính sách cùng nguồn đối với javascript, một số trang web quan trọng sẽ rất nguy hiểm
# Giải quyết vấn đề cross-domain
-1 Proxy phía frontend
-2 Proxy nginx
-3 cors giải quyết cross-domain
# cors: Chia sẻ tài nguyên giữa các nguồn gốc (Cross-Origin Resource Sharing), công nghệ backend, cốt lõi là thêm dữ liệu vào header phản hồi, cho phép trình duyệt tiếp nhận dữ liệu
CORS cần cả trình duyệt và máy chủ cùng hỗ trợ, trình duyệt IE không thể thấp hơn IE10
# Quy trình cơ bản của CORS
Trình duyệt chia yêu cầu CORS thành hai loại:
-Yêu cầu đơn giản (simple request)
-Yêu cầu không đơn giản (not-so-simple request)
# Yêu cầu đơn giản:
Trình duyệt gửi yêu cầu CORS đơn giản, chỉ cần thêm một trường Access-Control-Allow-Origin vào thông tin header
# Yêu cầu không đơn giản
Trình duyệt gửi yêu cầu CORS không đơn giản, sẽ gửi một yêu cầu options trước khi giao tiếp chính thức, gọi là yêu cầu "kiểm tra trước".
Trình duyệt trước tiên hỏi máy chủ, tên miền của trang web hiện tại có nằm trong danh sách cho phép của máy chủ không, nếu được phép, mới gửi yêu cầu thực sự
# Yêu cầu đơn giản là gì, yêu cầu không đơn giản là gì
-Đáp ứng hai điều kiện sau, đây là yêu cầu đơn giản
-1 Phương thức yêu cầu là một trong ba phương thức sau:
HEAD
GET
POST
-2 Thông tin header HTTP của yêu cầu không vượt quá các trường sau:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type: chỉ giới hạn ba giá trị application/x-www-form-urlencoded, multipart/form-data, text/plain
# Giải quyết cross-domain, sử dụng công nghệ cors, viết trong phản hồi: Nếu tự viết, cần viết một middleware, mỗi yêu cầu đều đi, trong process_response viết mã sau là được
def test(request):
print(request.method)
# Nếu tự viết, cần viết một middleware, mỗi yêu cầu đều đi, trong process_response viết mã sau là được
# Giải quyết yêu cầu đơn giản
res=HttpResponse('ok')
res['Access-Control-Allow-Origin']='*'
# Giải quyết yêu cầu không đơn giản
if request.method=='OPTIONS':
res['Access-Control-Allow-Headers'] = 'Content-Type'
return res
# Mô-đun bên thứ ba, đã giải quyết vấn đề này, chỉ cần tích hợp vào, sử dụng được---》django
-Bước đầu tiên: Cài đặt django-cors-headers
-Bước thứ hai: Đăng ký app<br></br>
INSTALLED_APPS = (
...
'corsheaders',
...
)
-Bước thứ ba: Thêm middleware
-Bước thứ tư: Cấu hình trong tệp cấu hình
CORS_ALLOW_HEADERS = ( 'XMLHttpRequest', 'X_FILENAME', 'accept-encoding', 'authorization', 'content-type', 'dnt', 'origin', 'user-agent', 'x-csrftoken', 'x-requested-with', 'Pragma', )
8. Giới thiệu git
========
Backend, viết một API, hoàn thành một chức năng, trong công ty, khi hoàn thành chức năng, cần đưa mã vào kho từ xa
Trong công ty, phát triển协同, quản lý phiên bản cần sử dụng phần mềm: svn, git
Tải xuống: Cài đặt trên hệ điều hành
-https://git-scm.com/downloads
-Nhấn下一步 liên tục
-Bất kỳ vị trí nào nhấn chuột phải, nếu có hai thứ (【git gui here】 【git bash here】), nghĩa là cài đặt thành công
Cấu hình git trong pycharm
-------------
github , gitee phần mềm mã nguồn mở,
Tải xuống thành zip, sử dụng pycharm mở
Sử dụng pycharm kéo trực tiếp xuống, mở---》Cấu hình pycharm
-Trong settings tìm kiếm git, cấu hình tệp thực thi git đã cài đặt
Sau này tải xuống phần mềm mã nguồn mở: vcs--->get from version contral--->Điền đường dẫn---->Clone xuống là được
=