Flask之SQLAlchemy,flask_session以及藍圖


數據庫操作

ORM

ORM 全拼 Object-Relation Mapping,中文意為 對象-關系映射。主要實現模型對象到關系數據庫數據的映射

優點 :

  • 只需要面向對象編程, 不需要面向數據庫編寫代碼.

    • 對數據庫的操作都轉化成對類屬性和方法的操作.

    • 不用編寫各種數據庫的sql語句.

  • 實現了數據模型與數據庫的解耦, 屏蔽了不同數據庫操作上的差異.

    • 不再需要關注當前項目使用的是哪種數據庫。

    • 通過簡單的配置就可以輕松更換數據庫, 而不需要修改代碼.

缺點 :

  • 相比較直接使用SQL語句操作數據庫,有性能損失.

  • 根據對象的操作轉換成SQL語句,根據查詢的結果轉化成對象, 在映射過程中有性能損失.

 

Flask-SQLAlchemy

flask默認提供模型操作,但是並沒有提供ORM,所以一般開發的時候我們會采用flask-SQLAlchemy模塊來實現ORM操作。

SQLAlchemy是一個關系型數據庫框架,它提供了高層的 ORM 和底層的原生數據庫的操作。flask-sqlalchemy 是一個簡化了 SQLAlchemy 操作的flask擴展。

SQLAlchemy: https://www.sqlalchemy.org/

 

安裝 flask-sqlalchemy

pip install flask-sqlalchemy

如果連接的是 mysql 數據庫,需要安裝 mysqldb 驅動

pip install flask-mysqldb

 

數據庫連接設置

  • 在 Flask-SQLAlchemy 中,數據庫使用URL指定,而且程序使用的數據庫必須保存到Flask配置對象的 SQLALCHEMY_DATABASE_URI 鍵中

app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test'
  • 其他設置

# 動態追蹤修改設置,如未設置只會提示警告
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
#查詢時會顯示原始SQL語句
app.config['SQLALCHEMY_ECHO'] = True
  • 配置完成需要去 MySQL 中創建項目所使用的數據庫

$ mysql -uroot -p123456
$ create database flaskdemo charset=utf8;

 

 

常用的SQLAlchemy字段類型

類型名 python中類型 說明
Integer int 普通整數,一般是32位
SmallInteger int 取值范圍小的整數,一般是16位
BigInteger int或long 不限制精度的整數
Float float 浮點數
Numeric decimal.Decimal 普通整數,一般是32位
String str 變長字符串
Text str 變長字符串,對較長或不限長度的字符串做了優化
Unicode unicode 變長Unicode字符串
UnicodeText unicode 變長Unicode字符串,對較長或不限長度的字符串做了優化
Boolean bool 布爾值
Date datetime.date 時間
Time datetime.datetime 日期和時間
LargeBinary str 二進制文件

常用的SQLAlchemy列選項

選項名 說明
primary_key 如果為True,代表表的主鍵
unique 如果為True,代表這列不允許出現重復的值
index 如果為True,為這列創建索引,提高查詢效率
nullable 如果為True,允許有空值,如果為False,不允許有空值
default 為這列定義默認值

常用的SQLAlchemy關系選項

選項名 說明
backref 在關系的另一模型中添加反向引用,用於設置外鍵名稱,在1查多的
primary join 明確指定兩個模型之間使用的聯結條件
uselist 如果為False,不使用列表,而使用標量值
order_by 指定關系中記錄的排序方式
secondary 指定多對多關系中關系表的名字
secondary join 在SQLAlchemy中無法自行決定時,指定多對多關系中的二級聯結條件

 

 

數據庫基本操作

  • 在Flask-SQLAlchemy中,插入、修改、刪除操作,均由數據庫會話管理。

    • 會話用 db.session 表示。在准備把數據寫入數據庫前,要先將數據添加到會話中然后調用 commit() 方法提交會話。

  • 在 Flask-SQLAlchemy 中,查詢操作是通過 query 對象操作數據。

    • 最基本的查詢是返回表中所有數據,可以通過過濾器進行更精確的數據庫查詢。

在視圖函數中定義模型類

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
​
​
app = Flask(__name__)
​
#設置連接數據庫的URL
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test'
​
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
#查詢時會顯示原始SQL語句
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
​
class Role(db.Model):
    # 定義表名
    __tablename__ = 'roles'
    # 定義列對象
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    us = db.relationship('User', backref='role')
​
    # repr()方法類似於django的__str__,用於打印模型對象時顯示的字符串信息
    def __repr__(self):
        return 'Role:%s'% self.name
​
class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    email = db.Column(db.String(64),unique=True)
    password = db.Column(db.String(64))
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
​
    def __repr__(self):
        return 'User:%s'%self.name
if __name__ == '__main__':
    app.run(debug=True)

 

 

模型之前的關聯

一對多

class Role(db.Model):
    ...
    #關鍵代碼
    us = db.relationship('User', backref='role', lazy='dynamic')
    ...
​
class User(db.Model):
    ...
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

 

  • 其中realtionship描述了Role和User的關系。在此文中,第一個參數為對應參照的類"User"

  • 第二個參數backref為類User申明新屬性的方法

  • 第三個參數lazy決定了什么時候SQLALchemy從數據庫中加載數據

    • 如果設置為子查詢方式(subquery),則會在加載完Role對象后,就立即加載與其關聯的對象,這樣會讓總查詢數量減少,但如果返回的條目數量很多,就會比較慢

      • 設置為 subquery 的話,role.users 返回所有數據列表

    • 另外,也可以設置為動態方式(dynamic),這樣關聯對象會在被使用的時候再進行加載,並且在返回前進行過濾,如果返回的對象數很多,或者未來會變得很多,那最好采用這種方式

      • 設置為 dynamic 的話,role.users 返回查詢對象,並沒有做真正的查詢,可以利用查詢對象做其他邏輯,比如:先排序再返回結果

多對多

registrations = db.Table('registrations',  
    db.Column('student_id', db.Integer, db.ForeignKey('students.id')),  
    db.Column('course_id', db.Integer, db.ForeignKey('courses.id'))  
)
​
class Course(db.Model):
    ...
​
class Student(db.Model):
    ...
    courses = db.relationship('Course',secondary=registrations,  
                                    backref='students',  
                                    lazy='dynamic')
 

 

常用的SQLAlchemy查詢過濾器

過濾器 說明
filter() 把過濾器添加到原查詢上,返回一個新查詢
filter_by() 把等值過濾器添加到原查詢上,返回一個新查詢
limit() 使用指定的值限定原查詢返回的結果
offset() 偏移原查詢返回的結果,返回一個新查詢
order_by() 根據指定條件對原查詢結果進行排序,返回一個新查詢
group_by() 根據指定條件對原查詢結果進行分組,返回一個新查詢

常用的SQLAlchemy查詢結果的方法

方法 說明
all() 以列表形式返回查詢的所有結果
first() 返回查詢的第一個結果,如果未查到,返回None
first_or_404() 返回查詢的第一個結果,如果未查到,返回404
get() 返回指定主鍵對應的行,如不存在,返回None
get_or_404() 返回指定主鍵對應的行,如不存在,返回404
count() 返回查詢結果的數量
paginate() 返回一個Paginate對象,它包含指定范圍內的結果

 

創建表:

db.create_all()  # 注意,create_all()方法執行的時候,需要放在模型的后面

刪除表

db.drop_all()

插入一條數據

ro1 = Role(name='admin')
db.session.add(ro1)
db.session.commit()
#再次插入一條數據
ro2 = Role(name='user')
db.session.add(ro2)
db.session.commit()

一次插入多條數據

us1 = User(name='wang',email='wang@163.com',password='123456',role_id=ro1.id)
us2 = User(name='zhang',email='zhang@189.com',password='201512',role_id=ro2.id)
us3 = User(name='chen',email='chen@126.com',password='987654',role_id=ro2.id)
us4 = User(name='zhou',email='zhou@163.com',password='456789',role_id=ro1.id)
us5 = User(name='tang',email='tang@163.com',password='158104',role_id=ro2.id)
us6 = User(name='wu',email='wu@gmail.com',password='5623514',role_id=ro2.id)
us7 = User(name='qian',email='qian@gmail.com',password='1543567',role_id=ro1.id)
us8 = User(name='liu',email='liu@163.com',password='867322',role_id=ro1.id)
us9 = User(name='li',email='li@163.com',password='4526342',role_id=ro2.id)
us10 = User(name='sun',email='sun@163.com',password='235523',role_id=ro2.id)
db.session.add_all([us1,us2,us3,us4,us5,us6,us7,us8,us9,us10])
db.session.commit()

練習:

查詢所有用戶數據
查詢有多少個用戶
查詢第1個用戶
查詢id為4的用戶[3種方式]
查詢名字結尾字符為g的所有數據[開始/包含]
查詢名字不等於wang的所有數據[2種方式]
查詢名字和郵箱都以 li 開頭的所有數據[2種方式]
查詢password是 `123456` 或者 `email` 以 `163.com` 結尾的所有數據
查詢id為 [1, 3, 5, 7, 9] 的用戶列表
查詢name為liu的角色數據
查詢所有用戶數據,並以郵箱排序
每頁3個,查詢第2頁的數據

 

 

filter_by精確查詢

返回名字等於wang的所有人

User.query.filter_by(name='wang').all()

first()返回查詢到的第一個對象

User.query.first()

all()返回查詢到的所有對象

User.query.all()

filter模糊查詢,返回名字結尾字符為g的所有數據。

User.query.filter(User.name.endswith('g')).all()

get():參數為主鍵,如果主鍵不存在沒有返回內容

User.query.get()

邏輯非,返回名字不等於wang的所有數據

not_ 相當於取反
from sqlalchemy import not_
User.query.filter(not_(User.name=='chen')).all()

邏輯與,需要導入and,返回and()條件滿足的所有數據

from sqlalchemy import and_
User.query.filter(and_(User.name!='wang',User.email.endswith('163.com'))).all()

邏輯或,需要導入or_

from sqlalchemy import or_
User.query.filter(or_(User.name!='wang',User.email.endswith('163.com'))).all()

查詢數據后刪除

user = User.query.first()
db.session.delete(user)
db.session.commit()
User.query.all()

更新數據

user = User.query.first()
user.name = 'dong'
db.session.commit()
User.query.first()

 

關聯查詢示例:

角色和用戶的關系是一對多的關系,一個角色可以有多個用戶,一個用戶只能屬於一個角色。

  • 查詢角色的所有用戶

#查詢roles表id為1的角色
ro1 = Role.query.get(1)
#查詢該角色的所有用戶
ro1.us.all()
  • 查詢用戶所屬角色

#查詢users表id為3的用戶
us1 = User.query.get(3)
#查詢用戶屬於什么角色
us1.role

 

查詢示例代碼:

  1 from flask import Flask
  2 from flask.json import jsonify
  3 
  4 from settings.dev import DevConfig
  5 from flask_sqlalchemy import SQLAlchemy
  6 import json
  7 from sqlalchemy import or_,and_,not_
  8 
  9 app = Flask(__name__,template_folder="templates",static_folder='static')
 10 app.config.from_object(DevConfig)
 11 
 12 # 初始化SQLAlchemy
 13 db = SQLAlchemy(app)
 14 
 15 
 16 class Role(db.Model):
 17     # 定義表名
 18     __tablename__ = 'roles' # 定義表名
 19     # 定義列對象
 20     id = db.Column(db.Integer,primary_key=True)
 21     name = db.Column(db.String(64),)
 22     us = db.relationship('User',backref='role', lazy='dynamic')
 23     def __repr__(self):
 24         return 'Role:%s'%self.name
 25 class User(db.Model):
 26     __tablename__ = "users"
 27     id = db.Column(db.Integer, primary_key=True)
 28     name = db.Column(db.String(64), )
 29     born = db.Column(db.Date, index=True)
 30     email = db.Column(db.String(64), unique=True)
 31     password = db.Column(db.String(64))
 32     role_id = db.Column(db.Integer,db.ForeignKey("roles.id"))
 33     def __repr__(self):
 34         return 'User:%s' % self.name
 35 
 36 @app.route("/all")
 37 def all():
 38     """all"""
 39     # 獲取所有數據
 40     user_list = User.query.all()
 41     user_list_dict = []
 42     for user in user_list:
 43         user_list_dict.append({
 44             "id":user.id,
 45             "name": user.name,
 46             "email":user.email
 47         })
 48     return jsonify(user_list_dict)
 49 
 50 
 51 @app.route("/filter_by")
 52 def filter_by():
 53     # first獲取一條數據
 54     user = User.query.filter_by(name="xiaoming").first()
 55     print(user)
 56     return "ok"
 57 
 58 @app.route("/get")
 59 def get():
 60     """get 根據主鍵查詢對應數據"""
 61     user = User.query.get(10)
 62     print(user)
 63     return "ok"
 64 
 65 @app.route("/mycount")
 66 def mycount():
 67     mycount = User.query.count()
 68     print(mycount)
 69     return "ok"
 70 
 71 @app.route("/like")
 72 def like():
 73     # 查詢name以字母"l"開頭的
 74     # 模型類名.query.filter(模型類名.字段.startswith("字符串")).all()
 75     # endswith()  結尾
 76 
 77     user_list = User.query.filter(User.name.startswith("l")).all()
 78     print(user_list)
 79     return "ok"
 80 
 81 @app.route("/logic1")
 82 def logic1():
 83     # 取反
 84     user_list = User.query.filter(User.name!="xiaoming").all()
 85     print(user_list)
 86     return "ok"
 87 
 88 @app.route("/logic2")
 89 def logic2():
 90     # 或者,多條件
 91     user_list = User.query.filter( or_(User.name=="xiaoming",User.name=="li") ).all()
 92     print(user_list)
 93     return "ok"
 94 
 95 @app.route("/logic3")
 96 def logic3():
 97     # 並且,多條件
 98     user_list = User.query.filter( and_(User.role_id==1,User.id>5) ).all()
 99     print(user_list)
100     return "ok"
101 
102 @app.route("/rel")
103 def rel():
104     # 外鍵查詢
105 
106     # 查詢roles表id為1的角色,並 查詢該角色的所有用戶
107     all_user = Role.query.get(1).us.all()
108 
109     # 查詢users表id為3的用戶,並查詢用戶屬於什么角色
110     us1 = User.query.get(3).role
111 
112     print("us1", us1)
113 
114     print("all_user",all_user)
115     return "ok"
116 
117 
118 if __name__ == '__main__':
119 
120     app.run(host="0.0.0.0", port=80)
View Code

 

 

數據庫遷移

  • 在開發過程中,需要修改數據庫模型,而且還要在修改之后更新數據庫。最直接的方式就是刪除舊表,但這樣會丟失數據。

  • 更好的解決辦法是使用數據庫遷移框架,它可以追蹤數據庫模式的變化,然后把變動應用到數據庫中。

  • 在Flask中可以使用Flask-Migrate擴展,來實現數據遷移。並且集成到Flask-Script中,所有操作通過命令就能完成。

  • 為了導出數據庫遷移命令,Flask-Migrate提供了一個MigrateCommand類,可以附加到flask-script的manager對象上。

首先要在虛擬環境中安裝Flask-Migrate。

pip install flask-migrate

 

代碼文件內容:

#coding=utf-8
from flask import Flask
​
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate,MigrateCommand
from flask_script import Shell,Manager
​
app = Flask(__name__)
manager = Manager(app)
​
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/Flask_test'
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
​
#第一個參數是Flask的實例,第二個參數是Sqlalchemy數據庫實例
migrate = Migrate(app,db) 
​
#manager是Flask-Script的實例,這條語句在flask-Script中添加一個db命令
manager.add_command('db',MigrateCommand)
​
#定義模型Role
class Role(db.Model):
    # 定義表名
    __tablename__ = 'roles'
    # 定義列對象
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    user = db.relationship('User', backref='role')
​
    #repr()方法顯示一個可讀字符串,
    def __repr__(self):
        return 'Role:'.format(self.name)
​
#定義用戶
class User(db.Model):
    __talbe__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, index=True)
    #設置外鍵
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
​
    def __repr__(self):
        return 'User:'.format(self.username)
​
​
if __name__ == '__main__':
    manager.run()

 

創建遷移倉庫

#這個命令會創建migrations文件夾,所有遷移文件都放在里面。
python manage.py db init

創建遷移腳本

  • 自動創建遷移腳本有兩個函數

    • upgrade():函數把遷移中的改動應用到數據庫中。

    • downgrade():函數則將改動刪除。

  • 自動創建的遷移腳本會根據模型定義和數據庫當前狀態的差異,生成upgrade()和downgrade()函數的內容。

  • 對比不一定完全正確,有可能會遺漏一些細節,需要進行檢查

python manage.py db migrate 

 

更新數據庫

python manage.py db upgrade 

 

返回以前的版本

可以根據history命令找到版本號,然后傳給downgrade命令:

python manage.py db history
​
輸出格式:<base> ->  版本號 (head), initial migration

 

回滾到指定版本

python manage.py db downgrade # 默認返回上一個版本
python manage.py db downgrade 版本號   # 返回到指定版本號對應的版本

 

數據遷移的步驟:

1. 初始化數據遷移的目錄
python manage.py db init

2. 數據庫的數據遷移版本初始化
python manage.py db migrate -m 'initial migration'

3. 升級版本[創建表]
python manage.py db upgrade 

4. 降級版本[刪除表]
python manage.py db downgrade

  

模塊推薦

文檔: https://faker.readthedocs.io/en/master/locales/zh_CN.html

github: https://github.com/joke2k/faker

 

 

 

flask-session

允許設置session到指定存儲的空間中, 文檔:

安裝命令: https://pythonhosted.org/Flask-Session/

pip install Flask-Session

使用session之前,必須配置一下配置項:

 SECRET_KEY = "luffycity" # session秘鑰

 

redis基本配置

app.config['SESSION_TYPE'] = 'redis'  # session類型為redis
app.config['SESSION_PERMANENT'] = False  # 如果設置為True,則關閉瀏覽器session就失效。
app.config['SESSION_USE_SIGNER'] = False  # 是否對發送到瀏覽器上session的cookie值進行加密
app.config['SESSION_KEY_PREFIX'] = 'session:'  # 保存到session中的值的前綴
app.config['SESSION_REDIS'] = redis.Redis(host='127.0.0.1', port='6379', password='123123')  # 用於連接redis的配置
​
Session(app)

 

SQLAlchemy基本配置

db = SQLAlchemy(app)
​
app.config['SESSION_TYPE'] = 'sqlalchemy'  # session類型為sqlalchemy
app.config['SESSION_SQLALCHEMY'] = db # SQLAlchemy對象
app.config['SESSION_SQLALCHEMY_TABLE'] = 'session' # session要保存的表名稱
app.config['SESSION_PERMANENT'] = True  # 如果設置為True,則關閉瀏覽器session就失效。
app.config['SESSION_USE_SIGNER'] = False  # 是否對發送到瀏覽器上session的cookie值進行加密
app.config['SESSION_KEY_PREFIX'] = 'session:'  # 保存到session中的值的前綴
​
Session(app)

 

 

 

 

 

藍圖 Blueprint

模塊化

隨着flask程序越來越復雜,我們需要對程序進行模塊化的處理,之前學習過python的模塊化管理,於是針對一個簡單的flask程序進行模塊化處理

 

簡單來說,Blueprint 是一個存儲操作方法的容器,這些操作在這個Blueprint 被注冊到一個應用之后就可以被調用,Flask 可以通過Blueprint來組織URL以及處理請求。

Flask使用Blueprint讓應用實現模塊化,在Flask中,Blueprint具有如下屬性:

  • 一個應用可以具有多個Blueprint

  • 可以將一個Blueprint注冊到任何一個未使用的URL下比如 “/”、“/sample”或者子域名

  • 在一個應用中,一個模塊可以注冊多次

  • Blueprint可以單獨具有自己的模板、靜態文件或者其它的通用操作方法,它並不是必須要實現應用的視圖和函數的

  • 在一個應用初始化時,就應該要注冊需要使用的Blueprint

但是一個Blueprint並不是一個完整的應用,它不能獨立於應用運行,而必須要注冊到某一個應用中。

 

Blueprint對象用起來和一個應用/Flask對象差不多,最大的區別在於一個 藍圖對象沒有辦法獨立運行,必須將它注冊到一個應用對象上才能生效

使用藍圖可以分為四個步驟

  1. 創建一個藍圖目錄,例如users,並在__init__.py文件中創建藍圖對象

users=Blueprint('users',__name__)
  1. 在這個藍圖目錄下, 創建views.py文件,保存當前藍圖使用的視圖函數

@admin.route('/')
def home():
    return 'user.home'
  1. users/init.py中引入views.py中所有的視圖函數

from flask import Blueprint
# 等同於原來在 manage.py里面的 app = Flask()
users=Blueprint('users',__name__)
​
from .views import *
  1. 在主應用manage.py文件中的app對象上注冊這個users藍圖對象

from users import users
app.register_blueprint(users,url_prefix='/users')

 

當這個應用啟動后,通過/users/可以訪問到藍圖中定義的視圖函數

 

運行機制

  • 藍圖是保存了一組將來可以在應用對象上執行的操作,注冊路由就是一種操作

  • 當在應用對象上調用 route 裝飾器注冊路由時,這個操作將修改對象的url_map路由表

  • 然而,藍圖對象根本沒有路由表,當我們在藍圖對象上調用route裝飾器注冊路由時,它只是在內部的一個延遲操作記錄列表defered_functions中添加了一個項

  • 當執行應用對象的 register_blueprint() 方法時,應用對象將從藍圖對象的 defered_functions 列表中取出每一項,並以自身作為參數執行該匿名函數,即調用應用對象的 add_url_rule() 方法,這將真正的修改應用對象的路由表

 

藍圖的url前綴

  • 當我們在應用對象上注冊一個藍圖時,可以指定一個url_prefix關鍵字參數(這個參數默認是/)

  • 在應用最終的路由表 url_map中,在藍圖上注冊的路由URL自動被加上了這個前綴,這個可以保證在多個藍圖中使用相同的URL規則而不會最終引起沖突,只要在注冊藍圖時將不同的藍圖掛接到不同的自路徑即可

  • url_for

url_for('admin.index') # /admin/

注冊靜態路由

和應用對象不同,藍圖對象創建時不會默認注冊靜態目錄的路由。需要我們在 創建時指定 static_folder 參數。

下面的示例將藍圖所在目錄下的static_admin目錄設置為靜態目錄

admin = Blueprint("admin",__name__,static_folder='static_admin')
app.register_blueprint(admin,url_prefix='/admin')

 

現在就可以使用/admin/static_admin/ 訪問static_admin目錄下的靜態文件了 定制靜態目錄URL規則 :可以在創建藍圖對象時使用 static_url_path 來改變靜態目錄的路由。下面的示例將為 static_admin 文件夾的路由設置為 /lib

admin = Blueprint("admin",__name__,static_folder='static_admin',static_url_path='/lib')
app.register_blueprint(admin,url_prefix='/admin')

 

 

設置模版目錄

藍圖對象默認的模板目錄為系統的模版目錄,可以在創建藍圖對象時使用 template_folder 關鍵字參數設置模板目錄

admin = Blueprint('admin',__name__,template_folder='my_templates')

注:如果在 templates 中存在和 my_templates 同名文件,則系統會優先使用 templates 中的文件


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM