Django-Ninja 中的多数据库支持
在现代Web应用开发中,经常需要处理来自多个数据源的数据。Django-Ninja是一个轻量级的Django API框架,它提供了简单易用的方式来构建RESTful API。然而,对于多数据库的支持,Django-Ninja本身并没有直接提供特性,而是依赖于Django的核心多数据库支持功能。
本文将详细介绍如何在Django-Ninja项目中配置和使用多数据库,以及如何在API视图中指定不同的数据库连接。我们将通过一个具体的例子来展示整个过程。
一、多数据库配置
在Django中,我们可以配置多个数据库连接,每个连接都有一个唯一的别名。这些配置项位于项目的settings.py
文件中。让我们来看一下如何设置两个数据库连接:一个用于主应用,另一个用于只读副本。
## 步骤 1: 配置多数据库
在settings.py
中定义两个数据库连接,分别为default
和readonly
:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'main_db',
'USER': 'main_user',
'PASSWORD': 'main_password',
'HOST': 'localhost',
'PORT': '',
},
'readonly': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'readonly_db',
'USER': 'readonly_user',
'PASSWORD': 'readonly_password',
'HOST': 'localhost',
'PORT': '',
},
}
这里我们使用PostgreSQL作为示例数据库,你可以根据实际情况选择其他数据库引擎。
二、模型和迁移
接下来我们需要创建一些模型,并且为每个数据库定义路由规则。
## 步骤 2: 创建模型
我们将在models.py
文件中定义两个模型:Article
和Comment
。
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
class Meta:
db_table = "article"
class Comment(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE)
text = models.CharField(max_length=200)
class Meta:
db_table = "comment"
## 步骤 3: 定义数据库路由
为了确保Article
和Comment
分别存储在不同的数据库中,我们需要创建一个数据库路由文件db_router.py
:
from django.db import router
class DatabaseAppsRouter(object):
def db_for_read(self, model, **hints):
if model._meta.app_label == 'myapp':
return 'readonly'
return None
def db_for_write(self, model, **hints):
if model._meta.app_label == 'myapp':
return 'default'
return None
def allow_relation(self, obj1, obj2, **hints):
db_list = ('default', 'readonly')
if obj1._state.db in db_list and obj2._state.db in db_list:
return True
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
if app_label == 'myapp':
return db in ('default', 'readonly')
return None
在settings.py
中注册这个路由:
DATABASE_ROUTERS = ['myapp.db_router.DatabaseAppsRouter']
接下来,我们需要创建数据库表。确保你已经创建了数据库并更新了数据库连接信息。
python manage.py makemigrations
python manage.py migrate
三、创建API视图
现在我们将使用Django-Ninja来创建API端点,并在视图中使用多数据库支持。
## 步骤 4: 安装Django-Ninja
确保你已经安装了Django-Ninja:
pip install django-ninja
## 步骤 5: 创建API视图
在views.py
文件中,我们将创建一个API视图来获取所有文章和评论。
from ninja import NinjaAPI
from .models import Article, Comment
from django.db import connection
api = NinjaAPI()
@api.get("/articles/")
def list_articles(request):
with connection.cursor() as cursor:
cursor.execute("SELECT * FROM article")
articles = cursor.fetchall()
return [{"id": row[0], "title": row[1], "content": row[2]} for row in articles]
@api.get("/comments/")
def list_comments(request):
with connection.cursor() as cursor:
cursor.execute("SELECT * FROM comment")
comments = cursor.fetchall()
return [{"id": row[0], "article_id": row[1], "text": row[2]} for row in comments]
注意,我们使用了connection
对象来执行SQL查询。在实际生产环境中,我们通常会使用Django的ORM来操作数据库,但在本例中为了展示不同数据库的使用,我们直接使用原生SQL。
四、测试API端点
最后,我们来测试一下API端点是否按预期工作。
## 步骤 6: 运行服务器
启动Django开发服务器:
python manage.py runserver
访问http://127.0.0.1:8000/api/docs
以查看API文档,并测试/articles/
和/comments/
端点。
五、总结
本文详细介绍了如何在Django-Ninja项目中配置和使用多数据库。我们通过配置数据库连接、定义模型、设置数据库路由、创建API视图和测试API端点来实现这一目标。多数据库支持可以帮助我们更好地管理和扩展应用程序,尤其是在需要读写分离或者跨多个数据源的情况下。
完整代码示例
下面是完整的代码示例,包括settings.py
、models.py
、db_router.py
和views.py
。
# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'main_db',
'USER': 'main_user',
'PASSWORD': 'main_password',
'HOST': 'localhost',
'PORT': '',
},
'readonly': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'readonly_db',
'USER': 'readonly_user',
'PASSWORD': 'readonly_password',
'HOST': 'localhost',
'PORT': '',
},
}
DATABASE_ROUTERS = ['myapp.db_router.DatabaseAppsRouter']
# models.py
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
class Meta:
db_table = "article"
class Comment(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE)
text = models.CharField(max_length=200)
class Meta:
db_table = "comment"
# db_router.py
from django.db import router
class DatabaseAppsRouter(object):
def db_for_read(self, model, **hints):
if model._meta.app_label == 'myapp':
return 'readonly'
return None
def db_for_write(self, model, **hints):
if model._meta.app_label == 'myapp':
return 'default'
return None
def allow_relation(self, obj1, obj2, **hints):
db_list = ('default', 'readonly')
if obj1._state.db in db_list and obj2._state.db in db_list:
return True
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
if app_label == 'myapp':
return db in ('default', 'readonly')
return None
# views.py
from ninja import NinjaAPI
from .models import Article, Comment
from django.db import connection
api = NinjaAPI()
@api.get("/articles/")
def list_articles(request):
with connection.cursor() as cursor:
cursor.execute("SELECT * FROM article")
articles = cursor.fetchall()
return [{"id": row[0], "title": row[1], "content": row[2]} for row in articles]
@api.get("/comments/")
def list_comments(request):
with connection.cursor() as cursor:
cursor.execute("SELECT * FROM comment")
comments = cursor.fetchall()
return [{"id": row[0], "article_id": row[1], "text": row[2]} for row in comments]