MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Python Flask与Django的数据库操作指南

2023-08-071.8k 阅读

Python Flask与Django的数据库操作指南

Flask数据库操作

Flask是一个轻量级的Python web框架,其核心设计理念是简洁、灵活。在处理数据库操作时,Flask本身并不内置特定的数据库支持,但借助一些优秀的第三方扩展库,我们可以轻松地与各种数据库进行交互。其中,SQLAlchemy是一个非常流行的数据库抽象层库,它允许我们使用Python代码来操作多种数据库,如MySQL、PostgreSQL、SQLite等。

安装SQLAlchemy

在开始使用SQLAlchemy之前,我们需要先安装它。可以使用pip命令进行安装:

pip install flask-sqlalchemy

初始化SQLAlchemy

在Flask应用中,我们首先要初始化SQLAlchemy对象。以下是一个简单的Flask应用示例,展示了如何初始化SQLAlchemy:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] ='sqlite:///test.db'
db = SQLAlchemy(app)

在上述代码中,我们通过app.config['SQLALCHEMY_DATABASE_URI']指定了数据库的连接字符串。这里使用的是SQLite数据库,数据库文件名为test.db。如果要使用其他数据库,如MySQL,连接字符串的格式会有所不同,例如:mysql+pymysql://username:password@host:port/database_name

定义数据库模型

在SQLAlchemy中,数据库表是通过定义Python类来表示的,这些类继承自db.Model。下面我们定义一个简单的用户表模型:

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)

    def __repr__(self):
        return f'<User {self.username}>'

在上述代码中,id字段是主键,usernameemail字段都设置为唯一且不能为空。__repr__方法用于定义对象的字符串表示形式,方便调试和日志记录。

创建数据库表

定义好模型后,我们可以通过以下代码来创建数据库表:

with app.app_context():
    db.create_all()

app.app_context()用于创建一个应用上下文,确保数据库操作在正确的Flask应用环境中执行。

添加数据

要向数据库中添加数据,我们需要创建模型类的实例,并将其添加到数据库会话中,然后提交会话。示例如下:

new_user = User(username='testuser', email='test@example.com')
with app.app_context():
    db.session.add(new_user)
    db.session.commit()

查询数据

SQLAlchemy提供了丰富的查询方法。例如,要查询所有用户:

with app.app_context():
    users = User.query.all()
    for user in users:
        print(user.username, user.email)

要根据条件查询,比如查询用户名是testuser的用户:

with app.app_context():
    user = User.query.filter_by(username='testuser').first()
    if user:
        print(user.email)

更新数据

更新数据需要先查询到要更新的对象,然后修改其属性,最后提交会话。示例如下:

with app.app_context():
    user = User.query.filter_by(username='testuser').first()
    if user:
        user.email = 'newemail@example.com'
        db.session.commit()

删除数据

删除数据同样需要先查询到对象,然后从会话中删除并提交。示例如下:

with app.app_context():
    user = User.query.filter_by(username='testuser').first()
    if user:
        db.session.delete(user)
        db.session.commit()

Django数据库操作

Django是一个功能强大的Python web框架,它内置了对数据库操作的支持。Django使用自己的对象关系映射(ORM)系统,允许开发者使用Python代码来操作数据库,而无需编写SQL语句。Django默认支持多种数据库,如SQLite、MySQL、PostgreSQL等。

配置数据库

在Django项目的settings.py文件中,我们可以配置数据库连接。以下是使用SQLite数据库的配置示例:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

如果要使用其他数据库,如MySQL,需要修改ENGINEdjango.db.backends.mysql,并添加USERPASSWORDHOSTPORT等配置项:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'your_database_name',
        'USER': 'your_username',
        'PASSWORD': 'your_password',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}

定义数据库模型

在Django中,数据库模型定义在models.py文件中。模型类继承自models.Model。以下是一个简单的用户模型示例:

from django.db import models

class User(models.Model):
    username = models.CharField(max_length=80, unique=True)
    email = models.EmailField(unique=True)

    def __str__(self):
        return self.username

与Flask的SQLAlchemy类似,usernameemail字段都设置为唯一。__str__方法用于定义对象的字符串表示形式。

创建数据库表

在定义好模型后,我们需要运行以下命令来创建数据库表:

python manage.py makemigrations
python manage.py migrate

makemigrations命令用于生成数据库迁移文件,记录模型的更改。migrate命令则将这些迁移应用到数据库中,创建实际的表结构。

添加数据

要向数据库中添加数据,我们可以创建模型类的实例,并调用save方法。示例如下:

from myapp.models import User
new_user = User(username='testuser', email='test@example.com')
new_user.save()

查询数据

Django提供了强大的查询API。例如,查询所有用户:

from myapp.models import User
users = User.objects.all()
for user in users:
    print(user.username, user.email)

根据条件查询,比如查询用户名是testuser的用户:

from myapp.models import User
user = User.objects.filter(username='testuser').first()
if user:
    print(user.email)

更新数据

更新数据可以先查询到对象,然后修改其属性并调用save方法。示例如下:

from myapp.models import User
user = User.objects.filter(username='testuser').first()
if user:
    user.email = 'newemail@example.com'
    user.save()

删除数据

删除数据同样先查询到对象,然后调用delete方法。示例如下:

from myapp.models import User
user = User.objects.filter(username='testuser').first()
if user:
    user.delete()

Flask与Django数据库操作对比

  1. 数据库配置方式
    • Flask:通过app.config来配置数据库连接字符串,灵活性较高,可以在运行时动态更改配置。但对于复杂的数据库设置,可能需要手动处理更多细节。
    • Django:在settings.py文件中进行集中配置,配置方式较为固定和统一。一旦配置完成,整个项目的数据库连接就确定下来,在运行时修改不太方便,但对于大型项目的整体数据库管理较为清晰。
  2. 模型定义
    • Flask(SQLAlchemy):模型类继承自db.Model,字段定义使用db.Column,语法相对更接近SQL的概念,对于熟悉SQL的开发者容易上手。字段类型的定义较为直接,例如db.Integerdb.String等。
    • Django:模型类继承自models.Model,字段定义使用models.CharFieldmodels.EmailField等,字段类型的命名更具Python风格,并且Django的模型字段有更多的内置验证和功能。例如models.EmailField会自动验证输入是否为有效的邮箱格式。
  3. 数据库迁移
    • Flask:SQLAlchemy本身没有内置的数据库迁移工具,通常需要借助其他扩展,如Flask - Migrate来实现数据库迁移。迁移过程相对灵活,但对于新手可能需要更多的学习成本来掌握迁移的流程和命令。
    • Django:内置了强大的数据库迁移系统,通过makemigrationsmigrate命令可以轻松管理数据库结构的变化。Django会自动跟踪模型的更改并生成相应的迁移文件,对于大型项目的数据库版本控制非常方便。
  4. 查询API
    • Flask(SQLAlchemy):查询API提供了丰富的方法,如filter_byfilter等,语法相对灵活,可以进行复杂的SQL查询构造。但对于一些复杂的聚合查询,可能需要编写更多的代码来实现。
    • Django:查询API简洁且功能强大,通过objects管理器提供了大量的查询方法,如allfilterexclude等。Django的查询API在处理复杂查询时,例如聚合、分组等操作,有更简洁和直观的语法,对于不熟悉SQL的开发者更容易上手。
  5. 事务处理
    • Flask(SQLAlchemy):事务处理通过数据库会话(db.session)来管理。可以使用try - except块来捕获异常并回滚事务,或者手动提交事务。例如:
try:
    new_user = User(username='testuser', email='test@example.com')
    db.session.add(new_user)
    db.session.commit()
except Exception as e:
    db.session.rollback()
    raise e
- **Django**:Django提供了多种事务管理方式,包括自动事务和手动事务。在视图函数中,可以使用`@transaction.atomic`装饰器来确保整个函数的数据库操作在一个事务中执行。例如:
from django.db import transaction

@transaction.atomic
def my_view(request):
    new_user = User(username='testuser', email='test@example.com')
    new_user.save()
    # 其他数据库操作
    return HttpResponse('Success')

高级数据库操作

  1. Flask高级操作
    • 多表关联查询:假设我们有两个模型,UserPostPost模型有一个外键指向User模型。
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, 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(120), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

要查询某个用户的所有文章,可以这样写:

with app.app_context():
    user = User.query.filter_by(username='testuser').first()
    if user:
        for post in user.posts:
            print(post.title)
- **使用原始SQL查询**:在某些情况下,我们可能需要执行原始的SQL查询。SQLAlchemy提供了`session.execute`方法。例如:
with app.app_context():
    result = db.session.execute('SELECT * FROM user WHERE username = :username', {'username': 'testuser'})
    for row in result:
        print(row)
  1. Django高级操作
    • 多表关联查询:同样假设我们有UserPost模型,Post模型有一个外键指向User模型。
class User(models.Model):
    username = models.CharField(max_length=80, unique=True)

class Post(models.Model):
    title = models.CharField(max_length=120)
    author = models.ForeignKey(User, on_delete=models.CASCADE)

要查询某个用户的所有文章,可以这样写:

from myapp.models import User
user = User.objects.filter(username='testuser').first()
if user:
    posts = user.post_set.all()
    for post in posts:
        print(post.title)
- **使用原始SQL查询**:Django也支持执行原始SQL查询。例如:
from myapp.models import User
users = User.objects.raw('SELECT * FROM myapp_user WHERE username = %s', ['testuser'])
for user in users:
    print(user.username)

性能优化

  1. Flask性能优化
    • 数据库连接池:使用连接池可以减少每次请求建立数据库连接的开销。可以使用SQLAlchemy结合DBUtils来实现连接池。首先安装DBUtils
pip install dbutils

然后配置SQLAlchemy使用连接池:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from dbutils.pooled_db import PooledDB

# 创建连接池
pool = PooledDB(
    creator=pymysql,
    host='127.0.0.1',
    port=3306,
    user='your_username',
    password='your_password',
    database='your_database',
    autocommit=True,
    maxconnections=10
)

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] ='mysql+pymysql://'
app.config['SQLALCHEMY_ENGINE_OPTIONS'] = {'pool': pool}
db = SQLAlchemy(app)
- **查询优化**:避免在循环中执行查询,尽量使用批量查询。例如,如果你需要获取多个用户的信息,不要循环逐个查询,而是一次性查询所有用户。
# 不好的做法
users = []
for username in ['user1', 'user2', 'user3']:
    user = User.query.filter_by(username=username).first()
    users.append(user)

# 好的做法
usernames = ['user1', 'user2', 'user3']
users = User.query.filter(User.username.in_(usernames)).all()
  1. Django性能优化
    • 使用select_related和prefetch_related:当进行多表关联查询时,select_relatedprefetch_related可以减少数据库查询次数。例如,当查询用户及其文章时:
# 使用select_related
users = User.objects.select_related('post_set').all()
for user in users:
    for post in user.post_set.all():
        print(post.title)

# 使用prefetch_related
users = User.objects.prefetch_related('post_set').all()
for user in users:
    for post in user.post_set.all():
        print(post.title)

select_related使用SQL的JOIN语句来一次性获取关联对象,适合一对一和多对一的关系。prefetch_related则是分别执行查询,然后在Python中合并结果,适合多对多和一对多的关系。 - 数据库索引优化:在Django模型中,可以为经常用于查询条件的字段添加索引。例如:

class User(models.Model):
    username = models.CharField(max_length=80, unique=True)
    email = models.EmailField(unique=True)

    class Meta:
        indexes = [
            models.Index(fields=['username']),
        ]

这样在根据username进行查询时,数据库可以使用索引来提高查询速度。

总结

Flask和Django在数据库操作方面各有特点。Flask轻量级且灵活,适合小型项目或对灵活性要求较高的场景,通过SQLAlchemy及其扩展可以实现强大的数据库操作。Django则功能全面,内置的数据库支持和迁移系统使得大型项目的数据库管理更加便捷,其查询API也非常适合快速开发。在实际项目中,我们应根据项目的规模、需求和团队技术栈来选择合适的框架进行数据库操作,并通过合理的优化手段来提升性能。无论是Flask还是Django,掌握好它们的数据库操作技巧,都能帮助我们高效地开发出高质量的Web应用。