【问题标题】:Using Django Rest Framework with a normalized database将 Django Rest Framework 与规范化数据库一起使用
【发布时间】:2018-07-13 06:22:53
【问题描述】:

DRF 的基本用例似乎是“资源”(在 API 端)到表(在数据库端)的一对一映射。

具体来说,假设我们有一个包含一个或多个“项目”的“区域设置”实体:“区域设置”表示一组项目中的通用地理和管理信息——如果它针对一个项目进行更改,我们需要针对一个项目进行更改全部。

我们在数据库中将其以规范化形式表示为LocaleProjects 表,而不是结合两者的非规范化Locale + Projects 表,在Projects 表中使用“Locale ID”作为外键。但是,我们希望对 api 用户隐藏这种规范化——我们只想公开一个 /project/ 端点,该端点返回与关联的 Locale 数据连接的 Project 数据,就好像它来自非规范化表一样。

当 DRF 中的单个 API 资源由后端数据库上的多个模型(以及表)组成时,如何表示它?

技术说明

  • 我在 posgtresql 9.6 中的后端
  • 这不是一个事务性数据库,因此我们预计每天更新 10-15 次,而不是每秒 100 次。

到目前为止我的想法

(1) 在后端创建一个物化视图来执行连接,然后在 Django 中创建一个单独存在的非托管模型以支持 GET 请求。

优点:似乎最适合与 Django/DRF 用例相结合,因为我只是 创建另一个表和模型(尽管具有只读功能)。

缺点:如果我想确保用户看到他们对基础数据的更改(例如,更改语言环境中的一些信息),我需要在每次更新后刷新物化视图。我可能会同时使用 REFRESH MATERIALIZED VIEW 来至少允许视图在更新时起作用。

所以,+1 表示易于实施,-1 表示货币。

(2) 在后端使用原始参数化 SQL 查询来设置 JOIN 并返回结果。

优点:避免更新后刷新物化视图的问题。

缺点:适应复杂的查询似乎很棘手——我认为这可能会变得脆弱。

(3) 非规范化,所以我们有一个LocaleProjects

优点:简单。

缺点:数据一致性受到影响。如果语言环境记录发生更改,则需要编写额外的后端查询来更新共享语言环境的记录。

任何额外的输入都会有所帮助。

【问题讨论】:

  • “DRF 的基本用例似乎是“资源”(在 API 端)到表(在数据库端)的一对一映射。事实并非如此。你为什么这么认为?
  • @philipxy 序列化程序是围绕模型构建的,模型是围绕表构建的。我没有看到太多展示如何创建一个实际表示两个表连接的模型。这就是为什么。如果我错了,我会很高兴,有人可以告诉我 DRF 如何处理资源表示为基础数据库中多个表的连接的情况。

标签: rest django-models django-rest-framework relational-database


【解决方案1】:

我的建议是使用Project 模型作为您的基本模型,并使用Locale 相关字段作为补充字段。以ListAPIView 为例。如果您需要创建或更新端点以同时更新ProjectLocale,就好像您有一个非规范化表一样,您可以覆盖createupdate 函数。

我假设locale 字段是从ProjectLocaleForeignKey

在你的serializers.py:

class ProjectWithLocaleSerializer(serializers.ModelSerializer):
    locale_field_1 = serializers.XXXField(source='locale.field_1')
    locale_field_2 = serializers.XXXField(source='locale.field_2')

    class Meta:
        model = Project
        fields = ('project_field_1', 'project_field_2', 'locale_field_1', 'locale_field_2', )

在你的views.py:

class ProjectWithLocaleListAPIView(ListAPIView):
    model = Project
    serializer_class = ProjectWithLocaleSerializer

    def get_queryset(self):
        return self.model.objects.select_related('locale')

【讨论】:

    猜你喜欢
    • 2015-03-29
    • 2012-08-02
    • 1970-01-01
    • 2018-03-23
    • 2014-12-08
    • 2015-04-29
    • 2018-10-23
    • 2016-07-23
    • 1970-01-01
    相关资源
    最近更新 更多