Trong phần này, chúng ta sẽ thiết lập cơ sở dữ liệu Postgres để lưu trữ kết quả đếm từ cũng như SQLAlchemy, Trình ánh xạ quan hệ đối tượng và Alembic để xử lý việc di chuyển cơ sở dữ liệu
Tiền thưởng miễn phí. Nhấp vào đây để truy cập vào video hướng dẫn Flask + Python miễn phí chỉ cho bạn cách xây dựng ứng dụng web Flask, từng bước một
cập nhật
- 02/09/2020. Đã nâng cấp lên phiên bản Python 3. 8. 1 cũng như các phiên bản mới nhất của Psycopg2, Flask-SQLAlchemy và Flask-Migrate. Xem để biết chi tiết. Rõ ràng cài đặt và sử dụng Flask-Script do thay đổi giao diện bên trong Flask-Migrate
- 22/03/2016. Đã nâng cấp lên phiên bản Python 3. 5. 1 cũng như các phiên bản mới nhất của Psycopg2, Flask-SQLAlchemy và Flask-Migrate. Xem để biết chi tiết
- 22/02/2015. Đã thêm hỗ trợ Python 3
Nhớ. Đây là những gì chúng tôi đang xây dựng - Một ứng dụng Flask tính toán các cặp tần số từ dựa trên văn bản từ một URL nhất định
- Phần một. Thiết lập môi trường phát triển cục bộ, sau đó triển khai cả môi trường dàn dựng và sản xuất trên Heroku
- Phần hai. Thiết lập cơ sở dữ liệu PostgreSQL cùng với SQLAlchemy và Alembic để xử lý việc di chuyển. [hiện hành]
- Một phần ba. Thêm vào logic back-end để cạo và sau đó xử lý số lượng từ từ một trang web bằng cách sử dụng các thư viện yêu cầu, BeautifulSoup và Bộ công cụ ngôn ngữ tự nhiên [NLTK]
- Phần Bốn. Triển khai hàng đợi tác vụ Redis để xử lý văn bản
- Phần Năm. Thiết lập Angular trên front-end để liên tục thăm dò back-end để xem yêu cầu đã được xử lý xong chưa
- Phần Sáu. Đẩy tới máy chủ dàn dựng trên Heroku - thiết lập Redis và hướng dẫn chi tiết cách chạy hai quy trình [web và worker] trên một Dyno
- Phần thứ bảy. Cập nhật giao diện người dùng để thân thiện hơn với người dùng
- Phần Tám. Tạo Chỉ thị góc tùy chỉnh để hiển thị biểu đồ phân phối tần suất bằng JavaScript và D3
Cần mã?
Yêu cầu cài đặt
Các công cụ được sử dụng trong phần này
- PostgreSQL [11. 6]
- Tâm linh2 [2. 8. 4] - bộ điều hợp Python cho Postgres
- Flask-SQLAlchemy [2. 4. 1] - Tiện ích mở rộng Flask cung cấp hỗ trợ SQLAlchemy
- Flask-Migrate [2. 5. 2] - tiện ích mở rộng hỗ trợ di chuyển cơ sở dữ liệu SQLAlchemy qua Alembic
Để bắt đầu, hãy cài đặt Postgres trên máy tính cục bộ của bạn, nếu bạn chưa có. Vì Heroku sử dụng Postgres, nên chúng tôi sẽ phát triển cục bộ trên cùng một cơ sở dữ liệu. Nếu bạn chưa cài đặt Postgres, Postgres. app là một cách dễ dàng để thiết lập và chạy cho người dùng Mac OS X. Tham khảo trang tải xuống để biết thêm thông tin
Khi bạn đã cài đặt và chạy Postgres, hãy tạo cơ sở dữ liệu có tên là
$ cd flask-by-example
9 để sử dụng làm cơ sở dữ liệu phát triển cục bộ của chúng tôi$ psql
# create database wordcount_dev;
CREATE DATABASE
# \q
Để sử dụng cơ sở dữ liệu mới được tạo trong ứng dụng Flask, chúng tôi cần cài đặt một số thứ
$ cd flask-by-example
0vào thư mục sẽ kích hoạt môi trường ảo và đặt các biến môi trường được tìm thấy trong tệp$ python -m pip install psycopg2==2.8.4 Flask-SQLAlchemy===2.4.1 Flask-Migrate==2.5.2 $ python -m pip freeze > requirements.txt
1 qua autoenv mà chúng tôi đã thiết lập trong phần 1$ python -m pip install psycopg2==2.8.4 Flask-SQLAlchemy===2.4.1 Flask-Migrate==2.5.2 $ python -m pip freeze > requirements.txt
$ python -m pip install psycopg2==2.8.4 Flask-SQLAlchemy===2.4.1 Flask-Migrate==2.5.2
$ python -m pip freeze > requirements.txt
Loại bỏ các quảng cáoNếu bạn đang dùng OS X và gặp sự cố khi cài đặt psycopg2, hãy xem bài viết về Stack Overflow này
Bạn có thể cần cài đặt
2 thay vì$ python -m pip install psycopg2==2.8.4 Flask-SQLAlchemy===2.4.1 Flask-Migrate==2.5.2 $ python -m pip freeze > requirements.txt
3 nếu quá trình cài đặt của bạn không thành công$ python -m pip install psycopg2==2.8.4 Flask-SQLAlchemy===2.4.1 Flask-Migrate==2.5.2 $ python -m pip freeze > requirements.txt
Cập nhật cấu hình
Thêm trường
$ python -m pip install psycopg2==2.8.4 Flask-SQLAlchemy===2.4.1 Flask-Migrate==2.5.2
$ python -m pip freeze > requirements.txt
4 vào lớp $ python -m pip install psycopg2==2.8.4 Flask-SQLAlchemy===2.4.1 Flask-Migrate==2.5.2
$ python -m pip freeze > requirements.txt
5 trong cấu hình của bạn. py để đặt ứng dụng của bạn sử dụng cơ sở dữ liệu mới được tạo trong quá trình phát triển [cục bộ], dàn dựng và sản xuấtimport os
class Config[object]:
...
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
cấu hình của bạn. tệp py bây giờ sẽ trông như thế này
import os
basedir = os.path.abspath[os.path.dirname[__file__]]
class Config[object]:
DEBUG = False
TESTING = False
CSRF_ENABLED = True
SECRET_KEY = 'this-really-needs-to-be-changed'
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
class ProductionConfig[Config]:
DEBUG = False
class StagingConfig[Config]:
DEVELOPMENT = True
DEBUG = True
class DevelopmentConfig[Config]:
DEVELOPMENT = True
DEBUG = True
class TestingConfig[Config]:
TESTING = True
Bây giờ khi cấu hình của chúng tôi được tải vào ứng dụng của chúng tôi, cơ sở dữ liệu thích hợp cũng sẽ được kết nối với nó
Tương tự như cách chúng ta đã thêm một biến môi trường trong bài trước, chúng ta sẽ thêm một biến
$ python -m pip install psycopg2==2.8.4 Flask-SQLAlchemy===2.4.1 Flask-Migrate==2.5.2
$ python -m pip freeze > requirements.txt
6. Chạy cái này trong terminal$ export DATABASE_URL="postgresql:///wordcount_dev"
Và sau đó thêm dòng đó vào của bạn. tập tin env
Trong ứng dụng của bạn. py nhập tệp SQLAlchemy và kết nối với cơ sở dữ liệu
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import os
app = Flask[__name__]
app.config.from_object[os.environ['APP_SETTINGS']]
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy[app]
from models import Result
@app.route['/']
def hello[]:
return "Hello World!"
@app.route['/']
def hello_name[name]:
return "Hello {}!".format[name]
if __name__ == '__main__':
app.run[]
Mô hình dữ liệu
Thiết lập mô hình cơ bản bằng cách thêm mô hình. tập tin py
from app import db
from sqlalchemy.dialects.postgresql import JSON
class Result[db.Model]:
__tablename__ = 'results'
id = db.Column[db.Integer, primary_key=True]
url = db.Column[db.String[]]
result_all = db.Column[JSON]
result_no_stop_words = db.Column[JSON]
def __init__[self, url, result_all, result_no_stop_words]:
self.url = url
self.result_all = result_all
self.result_no_stop_words = result_no_stop_words
def __repr__[self]:
return ''.format[self.id]
Ở đây chúng tôi đã tạo một bảng để lưu trữ kết quả đếm từ
Trước tiên, chúng tôi nhập kết nối cơ sở dữ liệu mà chúng tôi đã tạo trong ứng dụng của mình. py cũng như JSON từ SQLAlchemy's. Các cột JSON khá mới đối với Postgres và không có sẵn trong mọi cơ sở dữ liệu được SQLAlchemy hỗ trợ, vì vậy chúng tôi cần nhập cụ thể
Tiếp theo, chúng tôi đã tạo một lớp
$ python -m pip install psycopg2==2.8.4 Flask-SQLAlchemy===2.4.1 Flask-Migrate==2.5.2
$ python -m pip freeze > requirements.txt
7 và gán cho nó một tên bảng là $ python -m pip install psycopg2==2.8.4 Flask-SQLAlchemy===2.4.1 Flask-Migrate==2.5.2
$ python -m pip freeze > requirements.txt
8. Sau đó, chúng tôi đặt các thuộc tính mà chúng tôi muốn lưu trữ cho kết quả-
9 của kết quả mà chúng tôi đã lưu trữ$ python -m pip install psycopg2==2.8.4 Flask-SQLAlchemy===2.4.1 Flask-Migrate==2.5.2 $ python -m pip freeze > requirements.txt
0 mà chúng tôi đã đếm các từimport os class Config[object]: ... SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
- một danh sách đầy đủ các từ mà chúng tôi đếm
- một danh sách các từ mà chúng tôi đã đếm trừ đi các từ dừng [thêm về điều này sau]
Sau đó, chúng tôi đã tạo một phương thức
import os
class Config[object]:
...
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
1 sẽ chạy lần đầu tiên khi chúng tôi tạo một kết quả mới và cuối cùng, một phương thức import os
class Config[object]:
...
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
2 để biểu diễn đối tượng khi chúng tôi truy vấn nóDi chuyển cục bộ
Chúng tôi sẽ sử dụng Alembic, một phần của Flask-Migrate, để quản lý việc di chuyển cơ sở dữ liệu nhằm cập nhật lược đồ của cơ sở dữ liệu
Ghi chú. Flask-Migrate sử dụng công cụ CLI mới của Flask. Tuy nhiên, bài viết này sử dụng giao diện do Flask-Script cung cấp, đã được Flask-Migrate sử dụng trước đây. Để sử dụng nó, bạn cần cài đặt nó qua
$ python -m pip install Flask-Script==2.0.6 $ python -m pip freeze > requirements.txt
Tạo một tệp mới có tên là quản lý. py
import os
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from app import app, db
app.config.from_object[os.environ['APP_SETTINGS']]
migrate = Migrate[app, db]
manager = Manager[app]
manager.add_command['db', MigrateCommand]
if __name__ == '__main__':
manager.run[]
Để sử dụng Flask-Migrate, chúng tôi đã nhập
import os
class Config[object]:
...
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
3 cũng như import os
class Config[object]:
...
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
4 và import os
class Config[object]:
...
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
5 để quản lý. tập tin py. Chúng tôi cũng đã nhập import os
class Config[object]:
...
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
6 và import os
class Config[object]:
...
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
7 để chúng tôi có quyền truy cập chúng từ bên trong tập lệnhĐầu tiên, chúng tôi thiết lập cấu hình của mình để lấy môi trường - dựa trên biến môi trường - đã tạo một phiên bản di chuyển, với
import os
class Config[object]:
...
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
6 và import os
class Config[object]:
...
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
7 làm đối số và thiết lập lệnh import os
basedir = os.path.abspath[os.path.dirname[__file__]]
class Config[object]:
DEBUG = False
TESTING = False
CSRF_ENABLED = True
SECRET_KEY = 'this-really-needs-to-be-changed'
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
class ProductionConfig[Config]:
DEBUG = False
class StagingConfig[Config]:
DEVELOPMENT = True
DEBUG = True
class DevelopmentConfig[Config]:
DEVELOPMENT = True
DEBUG = True
class TestingConfig[Config]:
TESTING = True
0 để khởi tạo phiên bản import os
class Config[object]:
...
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
3 cho ứng dụng của chúng tôi. Cuối cùng, chúng tôi đã thêm lệnh import os
class Config[object]:
...
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
7 vào import os
basedir = os.path.abspath[os.path.dirname[__file__]]
class Config[object]:
DEBUG = False
TESTING = False
CSRF_ENABLED = True
SECRET_KEY = 'this-really-needs-to-be-changed'
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
class ProductionConfig[Config]:
DEBUG = False
class StagingConfig[Config]:
DEVELOPMENT = True
DEBUG = True
class DevelopmentConfig[Config]:
DEVELOPMENT = True
DEBUG = True
class TestingConfig[Config]:
TESTING = True
0 để chúng tôi có thể chạy di chuyển từ dòng lệnhĐể chạy quá trình di chuyển, hãy khởi tạo Alembic
$ cd flask-by-example
0Sau khi bạn chạy khởi tạo cơ sở dữ liệu, bạn sẽ thấy một thư mục mới có tên là “di chuyển” trong dự án. Điều này giữ thiết lập cần thiết để Alembic chạy di chuyển đối với dự án. Bên trong “migrations”, bạn sẽ thấy nó có một thư mục gọi là “versions”, thư mục này sẽ chứa các tập lệnh di chuyển khi chúng được tạo
Hãy tạo lần di chuyển đầu tiên của chúng ta bằng cách chạy lệnh
import os
basedir = os.path.abspath[os.path.dirname[__file__]]
class Config[object]:
DEBUG = False
TESTING = False
CSRF_ENABLED = True
SECRET_KEY = 'this-really-needs-to-be-changed'
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
class ProductionConfig[Config]:
DEBUG = False
class StagingConfig[Config]:
DEVELOPMENT = True
DEBUG = True
class DevelopmentConfig[Config]:
DEVELOPMENT = True
DEBUG = True
class TestingConfig[Config]:
TESTING = True
4$ cd flask-by-example
1Bây giờ bạn sẽ nhận thấy trong thư mục “phiên bản” của mình có một tệp di chuyển. Tệp này được Alembic tự động tạo dựa trên mô hình. Bạn có thể tự tạo [hoặc chỉnh sửa] tệp này;
Bây giờ chúng ta sẽ áp dụng các nâng cấp cho cơ sở dữ liệu bằng cách sử dụng lệnh
import os
basedir = os.path.abspath[os.path.dirname[__file__]]
class Config[object]:
DEBUG = False
TESTING = False
CSRF_ENABLED = True
SECRET_KEY = 'this-really-needs-to-be-changed'
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
class ProductionConfig[Config]:
DEBUG = False
class StagingConfig[Config]:
DEVELOPMENT = True
DEBUG = True
class DevelopmentConfig[Config]:
DEVELOPMENT = True
DEBUG = True
class TestingConfig[Config]:
TESTING = True
5$ cd flask-by-example
2Cơ sở dữ liệu hiện đã sẵn sàng để chúng tôi sử dụng trong ứng dụng của mình
$ cd flask-by-example
3Loại bỏ các quảng cáoDi chuyển từ xa
Cuối cùng, hãy áp dụng các lần di chuyển cho cơ sở dữ liệu trên Heroku. Tuy nhiên, trước tiên, chúng ta cần thêm các chi tiết của cơ sở dữ liệu dàn dựng và sản xuất vào cấu hình. tập tin py
Để kiểm tra xem chúng tôi đã thiết lập cơ sở dữ liệu trên máy chủ chạy chưa
$ cd flask-by-example
4Đảm bảo thay thế
6 bằng tên ứng dụng dàn dựng của bạnimport os basedir = os.path.abspath[os.path.dirname[__file__]] class Config[object]: DEBUG = False TESTING = False CSRF_ENABLED = True SECRET_KEY = 'this-really-needs-to-be-changed' SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL'] class ProductionConfig[Config]: DEBUG = False class StagingConfig[Config]: DEVELOPMENT = True DEBUG = True class DevelopmentConfig[Config]: DEVELOPMENT = True DEBUG = True class TestingConfig[Config]: TESTING = True
Vì chúng tôi không thấy biến môi trường cơ sở dữ liệu, chúng tôi cần thêm addon Postgres vào máy chủ dàn dựng. Để làm như vậy, hãy chạy lệnh sau
$ cd flask-by-example
57 là của addon Heroku Postgresimport os basedir = os.path.abspath[os.path.dirname[__file__]] class Config[object]: DEBUG = False TESTING = False CSRF_ENABLED = True SECRET_KEY = 'this-really-needs-to-be-changed' SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL'] class ProductionConfig[Config]: DEBUG = False class StagingConfig[Config]: DEVELOPMENT = True DEBUG = True class DevelopmentConfig[Config]: DEVELOPMENT = True DEBUG = True class TestingConfig[Config]: TESTING = True
Bây giờ khi chúng ta chạy lại
import os
basedir = os.path.abspath[os.path.dirname[__file__]]
class Config[object]:
DEBUG = False
TESTING = False
CSRF_ENABLED = True
SECRET_KEY = 'this-really-needs-to-be-changed'
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
class ProductionConfig[Config]:
DEBUG = False
class StagingConfig[Config]:
DEVELOPMENT = True
DEBUG = True
class DevelopmentConfig[Config]:
DEVELOPMENT = True
DEBUG = True
class TestingConfig[Config]:
TESTING = True
8, chúng ta sẽ thấy cài đặt kết nối cho cơ sở dữ liệu$ cd flask-by-example
6Tiếp theo, chúng tôi cần cam kết các thay đổi mà bạn đã thực hiện với git và đẩy tới máy chủ dàn dựng của bạn
$ cd flask-by-example
7Chạy các lần di chuyển mà chúng tôi đã tạo để di chuyển cơ sở dữ liệu theo giai đoạn của mình bằng cách sử dụng lệnh
import os
basedir = os.path.abspath[os.path.dirname[__file__]]
class Config[object]:
DEBUG = False
TESTING = False
CSRF_ENABLED = True
SECRET_KEY = 'this-really-needs-to-be-changed'
SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL']
class ProductionConfig[Config]:
DEBUG = False
class StagingConfig[Config]:
DEVELOPMENT = True
DEBUG = True
class DevelopmentConfig[Config]:
DEVELOPMENT = True
DEBUG = True
class TestingConfig[Config]:
TESTING = True
9$ cd flask-by-example
8Lưu ý cách chúng tôi chỉ chạy các lệnh
0, không phải các lệnh$ export DATABASE_URL="postgresql:///wordcount_dev"
1 hoặc$ export DATABASE_URL="postgresql:///wordcount_dev"
4 như trước đây. Chúng tôi đã thiết lập tệp di chuyển của mình và sẵn sàng hoạt động;import os basedir = os.path.abspath[os.path.dirname[__file__]] class Config[object]: DEBUG = False TESTING = False CSRF_ENABLED = True SECRET_KEY = 'this-really-needs-to-be-changed' SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL'] class ProductionConfig[Config]: DEBUG = False class StagingConfig[Config]: DEVELOPMENT = True DEBUG = True class DevelopmentConfig[Config]: DEVELOPMENT = True DEBUG = True class TestingConfig[Config]: TESTING = True
Bây giờ hãy làm tương tự cho sản xuất
- Thiết lập cơ sở dữ liệu cho ứng dụng sản xuất của bạn trên Heroku, giống như bạn đã làm với dàn dựng.
3$ export DATABASE_URL="postgresql:///wordcount_dev"
- Đẩy các thay đổi của bạn đến trang web sản xuất của bạn.
4 Lưu ý cách bạn không phải thực hiện bất kỳ thay đổi nào đối với tệp cấu hình - nó đang thiết lập cơ sở dữ liệu dựa trên biến môi trường$ export DATABASE_URL="postgresql:///wordcount_dev"
6 mới được tạo$ python -m pip install psycopg2==2.8.4 Flask-SQLAlchemy===2.4.1 Flask-Migrate==2.5.2 $ python -m pip freeze > requirements.txt
- Áp dụng di chuyển.
6$ export DATABASE_URL="postgresql:///wordcount_dev"
Giờ đây, cả trang dàn dựng và sản xuất của chúng tôi đều có cơ sở dữ liệu được thiết lập và được di chuyển - và sẵn sàng hoạt động
Khi bạn áp dụng di chuyển mới cho cơ sở dữ liệu sản xuất, có thể có thời gian ngừng hoạt động. Nếu đây là sự cố, bạn có thể thiết lập sao chép cơ sở dữ liệu bằng cách thêm cơ sở dữ liệu "người theo dõi" [thường được gọi là nô lệ]. Để biết thêm về điều này, hãy xem tài liệu chính thức của Heroku
Phần kết luận
Thế là xong phần 2. Nếu bạn muốn tìm hiểu sâu hơn về Flask, hãy xem loạt video đi kèm của chúng tôi
Tiền thưởng miễn phí. Nhấp vào đây để truy cập vào video hướng dẫn Flask + Python miễn phí chỉ cho bạn cách xây dựng ứng dụng web Flask, từng bước một
Trong Phần 3, chúng ta sẽ xây dựng chức năng đếm từ và gửi nó đến hàng đợi tác vụ để giải quyết quá trình xử lý đếm từ chạy lâu hơn
Hẹn gặp lại bạn lần sau. Chúc mừng
Đây là sản phẩm hợp tác giữa Cam Linke, đồng sáng lập Startup Edmonton và những người ở Real Python
Đánh dấu là đã hoàn thành
🐍 Thủ thuật Python 💌
Nhận một Thủ thuật Python ngắn và hấp dẫn được gửi đến hộp thư đến của bạn vài ngày một lần. Không có thư rác bao giờ. Hủy đăng ký bất cứ lúc nào. Được quản lý bởi nhóm Real Python
Gửi cho tôi thủ thuật Python »
Về Đội
Mỗi hướng dẫn tại Real Python được tạo bởi một nhóm các nhà phát triển để nó đáp ứng các tiêu chuẩn chất lượng cao của chúng tôi. Các thành viên trong nhóm đã làm việc trong hướng dẫn này là
Aldren
Florian
Michael
Bậc thầy Kỹ năng Python trong thế giới thực Với quyền truy cập không giới hạn vào Python thực
Tham gia với chúng tôi và có quyền truy cập vào hàng nghìn hướng dẫn, khóa học video thực hành và cộng đồng các Pythonistas chuyên gia
Nâng cao kỹ năng Python của bạn »
Chuyên gia Kỹ năng Python trong thế giới thực
Với quyền truy cập không giới hạn vào Python thực
Tham gia với chúng tôi và có quyền truy cập vào hàng ngàn hướng dẫn, khóa học video thực hành và cộng đồng Pythonistas chuyên gia
Nâng cao kỹ năng Python của bạn »
Bạn nghĩ sao?
Đánh giá bài viết này
Tweet Chia sẻ Chia sẻ EmailBài học số 1 hoặc điều yêu thích mà bạn đã học được là gì?
Mẹo bình luận. Những nhận xét hữu ích nhất là những nhận xét được viết với mục đích học hỏi hoặc giúp đỡ các sinh viên khác. và nhận câu trả lời cho các câu hỏi phổ biến trong cổng thông tin hỗ trợ của chúng tôi