Trong Flask, việc xây dựng ứng dụng có thể được thực hiện thông qua việc tổ chức mã nguồn thành các modules hoặc xây dựng services.
Cả hai cách tiếp cận này đều có những ưu điểm riêng về tính linh hoạt, và lựa chọn giữa chúng phụ thuộc vào quy mô và yêu cầu cụ thể của dự án.
Dưới đây là so sánh chi tiết giữa hai cách tiếp cận này:
Ưu điểm:
Nhược điểm:
Ưu điểm:
Nhược điểm:
Tóm lại, lựa chọn giữa xây dựng modules hay services trong Flask phụ thuộc vào quy mô, yêu cầu và mục tiêu của dự án cụ thể.
Nếu bạn mới bắt đầu hoặc làm việc với một ứng dụng nhỏ, việc sử dụng modules có thể là lựa chọn tốt hơn.
Ngược lại, nếu bạn đang xây dựng một hệ thống lớn với yêu cầu mở rộng cao, việc phân chia thành các services sẽ mang lại nhiều lợi ích hơn.
Dưới đây là một ví dụ về cách tổ chức mã nguồn của ứng dụng Flask theo mô hình modules.
Giả sử bạn đang xây dựng một ứng dụng web quản lý người dùng và bài viết.
Chúng ta sẽ tạo ra hai module chính: users và posts.
my_flask_app/ |-- app.py |-- config.py |-- requirements.txt |-- run.py |-- users/ | |-- __init__.py | |-- models.py | |-- routes.py | |-- forms.py | |-- templates/ | |-- users/ | |-- register.html | |-- login.html |-- posts/ | |-- __init__.py | |-- models.py | |-- routes.py | |-- forms.py | |-- templates/ | |-- posts/ | |-- create_post.html | |-- post.html |-- templates/ |-- base.html
from flask import Flask from config import Config def create_app(): app = Flask(__name__) app.config.from_object(Config) from users.routes import users from posts.routes import posts app.register_blueprint(users, url_prefix='/users') app.register_blueprint(posts, url_prefix='/posts') return app
class Config: SECRET_KEY = 'your_secret_key' SQLALCHEMY_DATABASE_URI = 'sqlite:///site.db'
from app import create_app app = create_app() if __name__ == '__main__': app.run(debug=True)
# users module initialization
from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(20), unique=True, nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) password = db.Column(db.String(60), nullable=False)
from flask import Blueprint, render_template users = Blueprint('users', __name__) @users.route('/register') def register(): return render_template('users/register.html') @users.route('/login') def login(): return render_template('users/login.html')
# posts module initialization
from flask_sqlalchemy import SQLAlchemy from datetime import datetime db = SQLAlchemy() class Post(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(100), nullable=False) date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) content = db.Column(db.Text, nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
from flask import Blueprint, render_template posts = Blueprint('posts', __name__) @posts.route('/new') def new_post(): return render_template('posts/create_post.html') @posts.route('/<int:post_id>') def post(post_id): return render_template('posts/post.html')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Flask App</title> </head> <body> <nav> <a href="/">Home</a> <a href="/users/register">Register</a> <a href="/users/login">Login</a> <a href="/posts/new">New Post</a> </nav> <div> {% block content %}{% endblock %} </div> </body> </html>
{% extends "base.html" %} {% block content %} <h2>Register</h2> <!-- Registration form here --> {% endblock %}
{% extends "base.html" %} {% block content %} <h2>Login</h2> <!-- Login form here --> {% endblock %}
{% extends "base.html" %} {% block content %} <h2>Create a New Post</h2> <!-- Post creation form here --> {% endblock %}
{% extends "base.html" %} {% block content %} <h2>Post</h2> <!-- Post content here --> {% endblock %}
Cách tổ chức này giúp mã nguồn trở nên rõ ràng, dễ quản lý và mở rộng khi ứng dụng phát triển.
Để sử dụng các modules users và posts trong ứng dụng Flask, bạn cần thực hiện các bước sau để khởi tạo và chạy ứng dụng.
Dưới đây là hướng dẫn chi tiết về cách thực hiện điều đó.
from flask import Flask from flask_sqlalchemy import SQLAlchemy from config import Config db = SQLAlchemy() def create_app(): app = Flask(__name__) app.config.from_object(Config) db.init_app(app) from users.routes import users from posts.routes import posts app.register_blueprint(users, url_prefix='/users') app.register_blueprint(posts, url_prefix='/posts') return app
from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(20), unique=True, nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) password = db.Column(db.String(60), nullable=False) posts = db.relationship('Post', backref='author', lazy=True)
from datetime import datetime from users.models import db, User class Post(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(100), nullable=False) date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) content = db.Column(db.Text, nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
# __init__.py
Tạo một tệp create_db.py để khởi tạo cơ sở dữ liệu:
from app import create_app, db app = create_app() with app.app_context(): db.create_all()
Chạy tập tin create_db.py để tạo cơ sở dữ liệu:
python create_db.py
Chạy tệp run.py để khởi động ứng dụng Flask:
python run.py
Bây giờ, bạn có thể truy cập vào các đường dẫn mà bạn đã định nghĩa trong các modules users và posts.
Bằng cách tổ chức mã nguồn theo mô hình modules, bạn có thể quản lý mã nguồn một cách rõ ràng và dễ mở rộng.
Các bước chính bao gồm:
Cấu trúc và tổ chức như trên giúp bạn dễ dàng mở rộng ứng dụng trong tương lai bằng cách thêm các modules mới hoặc cải tiến các modules hiện tại.
Khi các modules phụ thuộc vào nhau trong Flask, việc quản lý và sử dụng các dependencies này cần được thực hiện một cách cẩn thận để tránh các vấn đề về vòng lặp (circular imports).
Dưới đây là một số kỹ thuật để xử lý dependencies giữa các modules users và posts:
Bạn có thể sử dụng Flask application context để truy cập các dependencies trong các modules khác nhau mà không cần phải import trực tiếp.
Điều này giúp tránh các vấn đề về vòng lặp.
my_flask_app/ |-- app.py |-- config.py |-- requirements.txt |-- run.py |-- users/ | |-- __init__.py | |-- models.py | |-- routes.py | |-- forms.py | |-- templates/ | |-- users/ | |-- register.html | |-- login.html |-- posts/ | |-- __init__.py | |-- models.py | |-- routes.py | |-- forms.py | |-- templates/ | |-- posts/ | |-- create_post.html | |-- post.html |-- templates/ |-- base.html
from flask import Flask from flask_sqlalchemy import SQLAlchemy from config import Config db = SQLAlchemy() def create_app(): app = Flask(__name__) app.config.from_object(Config) db.init_app(app) from users.routes import users from posts.routes import posts app.register_blueprint(users, url_prefix='/users') app.register_blueprint(posts, url_prefix='/posts') with app.app_context(): from users.models import User from posts.models import Post db.create_all() return app
from app import db class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(20), unique=True, nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) password = db.Column(db.String(60), nullable=False) posts = db.relationship('Post', backref='author', lazy=True)
from app import db from datetime import datetime class Post(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(100), nullable=False) date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) content = db.Column(db.Text, nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
from flask import Blueprint, render_template from .models import User from posts.models import Post # Import Post model users = Blueprint('users', __name__) @users.route('/register') def register(): return render_template('users/register.html') @users.route('/login') def login(): return render_template('users/login.html') @users.route('/user/<int:user_id>') def user_posts(user_id): user = User.query.get_or_404(user_id) posts = Post.query.filter_by(user_id=user_id).all() return render_template('users/user_posts.html', user=user, posts=posts)
from flask import Blueprint, render_template from .models import Post from users.models import User # Import User model posts = Blueprint('posts', __name__) @posts.route('/new') def new_post(): return render_template('posts/create_post.html') @posts.route('/<int:post_id>') def post(post_id): post = Post.query.get_or_404(post_id) return render_template('posts/post.html', post=post) @posts.route('/author/<int:author_id>') def author_posts(author_id): author = User.query.get_or_404(author_id) posts = Post.query.filter_by(user_id=author_id).all() return render_template('posts/author_posts.html', author=author, posts=posts)
Một kỹ thuật khác để tránh vòng lặp là sử dụng lazy imports, tức là chỉ import khi cần thiết trong một hàm hoặc một phương thức thay vì ở đầu tệp.
from flask import Blueprint, render_template users = Blueprint('users', __name__) @users.route('/register') def register(): return render_template('users/register.html') @users.route('/login') def login(): return render_template('users/login.html') @users.route('/user/<int:user_id>') def user_posts(user_id): from .models import User from posts.models import Post user = User.query.get_or_404(user_id) posts = Post.query.filter_by(user_id=user_id).all() return render_template('users/user_posts.html', user=user, posts=posts)
from flask import Blueprint, render_template posts = Blueprint('posts', __name__) @posts.route('/new') def new_post(): return render_template('posts/create_post.html') @posts.route('/<int:post_id>') def post(post_id): from .models import Post post = Post.query.get_or_404(post_id) return render_template('posts/post.html', post=post) @posts.route('/author/<int:author_id>') def author_posts(author_id): from users.models import User from .models import Post author = User.query.get_or_404(author_id) posts = Post.query.filter_by(user_id=author_id).all() return render_template('posts/author_posts.html', author=author, posts=posts)
Một phương pháp khác là tạo một module riêng cho các models để chúng có thể được chia sẻ dễ dàng giữa các modules khác nhau mà không gây ra vấn đề về vòng lặp.
my_flask_app/ |-- app.py |-- config.py |-- requirements.txt |-- run.py |-- models.py |-- users/ | |-- __init__.py | |-- routes.py | |-- forms.py | |-- templates/ | |-- users/ | |-- register.html | |-- login.html |-- posts/ | |-- __init__.py | |-- routes.py | |-- forms.py | |-- templates/ | |-- posts/ | |-- create_post.html | |-- post.html |-- templates/ |-- base.html
from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(20), unique=True, nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) password = db.Column(db.String(60), nullable=False) posts = db.relationship('Post', backref='author', lazy=True) class Post(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(100), nullable=False) date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) content = db.Column(db.Text, nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
from flask import Flask from config import Config from models import db def create_app(): app = Flask(__name__) app.config.from_object(Config) db.init_app(app) from users.routes import users from posts.routes import posts app.register_blueprint(users, url_prefix='/users') app.register_blueprint(posts, url_prefix='/posts') with app.app_context(): db.create_all() return app
from flask import Blueprint, render_template from models import User, Post users = Blueprint('users', __name__) @users.route('/register') def register(): return render_template('users/register.html') @users.route('/login') def login(): return render_template('users/login.html') @users.route('/user/<int:user_id>') def user_posts(user_id): user = User.query.get_or_404(user_id) posts = Post.query.filter_by(user_id=user_id).all() return render_template('users/user_posts.html', user=user, posts=posts)
from flask import Blueprint, render_template from models import User, Post posts = Blueprint('posts', __name__) @posts.route('/new') def new_post(): return render_template('posts/create_post.html') @posts.route('/<int:post_id>') def post(post_id): post = Post.query.get_or_404(post_id) return render_template('posts/post.html', post=post) @posts.route('/author/<int:author_id>') def author_posts(author_id): author = User.query.get_or_404(author_id) posts = Post.query.filter_by(user_id=author_id).all() return render_template('posts/author_posts.html', author=author, posts=posts)
Bằng cách này, bạn có thể tổ chức mã nguồn một cách rõ ràng và tránh các vấn đề về vòng lặp.
Giảm việc lặp lại code khi sử dụng modules trong Flask có thể đạt được bằng cách tận dụng các kỹ thuật và mô hình như sau:
Sử dụng Blueprints để Tái Sử Dụng Mã:
Tạo Các Tiện Ích Chung:
Sử Dụng Base Templates:
Tái Sử Dụng Form và Validation:
Tạo Middleware hoặc Decorators Chung:
my_flask_app/ |-- app.py |-- config.py |-- requirements.txt |-- run.py |-- common/ | |-- __init__.py | |-- utils.py | |-- forms.py | |-- decorators.py |-- templates/ | |-- base.html |-- users/ | |-- __init__.py | |-- models.py | |-- routes.py | |-- templates/ | |-- users/ | |-- register.html | |-- login.html |-- posts/ | |-- __init__.py | |-- models.py | |-- routes.py | |-- templates/ | |-- posts/ | |-- create_post.html | |-- post.html
from flask import Flask from flask_sqlalchemy import SQLAlchemy from config import Config db = SQLAlchemy() def create_app(): app = Flask(__name__) app.config.from_object(Config) db.init_app(app) from users.routes import users from posts.routes import posts app.register_blueprint(users, url_prefix='/users') app.register_blueprint(posts, url_prefix='/posts') with app.app_context(): db.create_all() return app
from flask import flash def flash_message(message, category='info'): flash(message, category)
from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, SubmitField from wtforms.validators import DataRequired, Email, EqualTo class RegistrationForm(FlaskForm): username = StringField('Username', validators=[DataRequired()]) email = StringField('Email', validators=[DataRequired(), Email()]) password = PasswordField('Password', validators=[DataRequired()]) confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')]) submit = SubmitField('Sign Up') class LoginForm(FlaskForm): email = StringField('Email', validators=[DataRequired(), Email()]) password = PasswordField('Password', validators=[DataRequired()]) submit = SubmitField('Login')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Flask App</title> </head> <body> <nav> <a href="/">Home</a> <a href="/users/register">Register</a> <a href="/users/login">Login</a> <a href="/posts/new">New Post</a> </nav> <div> {% block content %}{% endblock %} </div> </body> </html>
{% extends "base.html" %} {% block content %} <h2>Register</h2> <form method="POST"> {{ form.hidden_tag() }} {{ form.username.label }} {{ form.username(size=32) }}<br> {{ form.email.label }} {{ form.email(size=32) }}<br> {{ form.password.label }} {{ form.password(size=32) }}<br> {{ form.confirm_password.label }} {{ form.confirm_password(size=32) }}<br> {{ form.submit() }} </form> {% endblock %}
from flask import Blueprint, render_template, redirect, url_for from common.forms import RegistrationForm, LoginForm from common.utils import flash_message users = Blueprint('users', __name__) @users.route('/register', methods=['GET', 'POST']) def register(): form = RegistrationForm() if form.validate_on_submit(): flash_message('Account created for {form.username.data}!', 'success') return redirect(url_for('users.login')) return render_template('users/register.html', form=form) @users.route('/login', methods=['GET', 'POST']) def login(): form = LoginForm() if form.validate_on_submit(): flash_message('Logged in successfully!', 'success') return redirect(url_for('posts.new_post')) return render_template('users/login.html', form=form)
from flask import redirect, url_for, flash from functools import wraps def login_required(f): @wraps(f) def decorated_function(*args, **kwargs): if not current_user.is_authenticated: flash('Please log in to access this page.', 'warning') return redirect(url_for('users.login')) return f(*args, **kwargs) return decorated_function
from flask import Blueprint, render_template from common.decorators import login_required from .forms import PostForm posts = Blueprint('posts', __name__) @posts.route('/new', methods=['GET', 'POST']) @login_required def new_post(): form = PostForm() if form.validate_on_submit(): flash_message('Your post has been created!', 'success') return redirect(url_for('posts.post', post_id=new_post.id)) return render_template('posts/create_post.html', form=form) @posts.route('/<int:post_id>') def post(post_id): post = Post.query.get_or_404(post_id) return render_template('posts/post.html', post=post)
Bằng cách áp dụng các kỹ thuật trên, bạn có thể giảm thiểu việc lặp lại mã, tăng tính tái sử dụng và dễ bảo trì mã nguồn trong ứng dụng Flask của mình.
#Mtips5s #Contact
Fanpage: https://www.facebook.com/mtipscoder
Group trao đổi, chia sẻ: https://www.facebook.com/groups/mtipscoder
Website: https://mtips5s.com
Youtube: https://mtips5s.com
Twitter(X): @takagiks99
Instagram: @khuongkara
Threads: @khuongkara
Google Maps: @khuongkara
#Base Code #Souce Code
Bộ công cụ My Self: @tools.mtips5s.com
Github: @github
Npm: @npm
Docker: @docker
Chúc các bạn thành công!
Leave A Comment