有很多方法可以构建 Django 项目。很难找到确保可维护性和可扩展性的设计。这是我的目标。

我一直在研究领域驱动设计以及如何将它与 Django REST 框架结合到 Django 中。我想设计一个健壮的架构,它易于记录,并且对协作和单独的项目都有效。不管我能否做到这一点,这次努力对我来说将是一次重要的经历。

该项目仍在进行中,DDD 中有一些我尚未完全探索的主题。我将尽我最大的努力研究它们,并希望在今年年底之前发布它的初始稳定版本。事不宜迟,让我们开始吧。

概述

这是初始结构:

project/
  api/
    migrations/
    services/
      blogs/
        read_blog.py
    __init__.py
    apps.py
  project/
    __init__.py
    asgi.py
    settings.py
    urls.py
    wsgi.py
  resources/
    migrations/
    repositories/
      base_repository.py
      blog_repository.py
    serializers/
      blog_serializer.py
    __init__.py
    admin.py
    apps.py
    models.py

进入全屏模式 退出全屏模式

目前,它拥有三个应用程序:apiprojectresources。确保创建它们并安装djangorestframeworkdjango-cors-headers软件包。

项目

项目文件夹是我们的核心应用程序。文件夹名称基于您为 django 项目输入的名称,因此您不必遵循本示例中提供的名称。默认情况下,这是存储设置、wsgi、asgi 和 url 的地方。我们还可以在此处存储其他文件,例如 JWT 的类、自定义中间件等。由于我们使用其他包,我们需要配置我们的设置文件:

项目/settings.py

INSTALLED_APPS = [
    …
    'corsheaders',
    'rest_framework',
    'api.apps.ApiConfig',
    'resources.apps.ResourcesConfig',
]

MIDDLEWARE = [
    …
    'corsheaders.middleware.CorsMiddleware',
    …
]

# this is set to true for now
CORS_ORIGIN_ALLOW_ALL = True

进入全屏模式 退出全屏模式

一旦我们建立了我们的 api 服务,我们稍后会重新访问这个文件夹。

资源

resources 文件夹是我们放置模型、存储库和序列化程序的地方。我们的模型将包含数据库表的模式,而我们的存储库将处理从持久层 (ORM) 获取对象。最后,序列化器会将我们的查询集呈现为 JSON。

资源/models.py

from django.contrib.auth.models import User
from django.db import models

class Blog(models.Model):
  content = models.TextField()
  summary = models.CharField(max_length=100)
  title = models.CharField(max_length=100)
  created_on = models.DateTimeField(auto_now_add=True)

  author = models.ForeignKey(
    User,
    on_delete=models.CASCADE,
    default=None
  )

  def __str__(self):
    return self.title

进入全屏模式 退出全屏模式

对于我们的存储库,我们需要一个基本存储库文件,其中注册了所有基本方法,并且可以由不同的模型存储库继承。每个模型存储库都可以有自己的聚合和复杂查询方法:

资源/存储库/基础_repository.py

from django.db import InternalError, DatabaseError
from django.http import Http404, HttpResponseServerError

class BaseRepository(object):
  def find(self, id, value_list=()):
    try:
      if len(value_list):
        return self.model.objects.get(pk=id).values(*value_list)
      else:
        return self.model.objects.get(pk=id)
    except self.model.DoesNotExist:
      raise Http404
    except InternalError:
      raise HttpResponseServerError
    except DatabaseError:
      raise Http404

进入全屏模式 退出全屏模式

资源/存储库/博客_repository.rb

from resources.models import Blog
from resources.repositories.base_repository import BaseRepository

class BlogRepository(BaseRepository):
  def __init__(self):
    self.model = Blog

进入全屏模式 退出全屏模式

资源/序列化器/博客_serializer.py

from rest_framework import serializers
from resources.models import Blog

class BlogSerializer(serializers.ModelSerializer):
  class Meta:
    model = Blog

    fields = [
      'id',
      'content'
      'summary',
      'title',
      'created_on'
    ]

进入全屏模式 退出全屏模式

您可能想知道存储库的重要性是什么,因为我们已经有了 ORM。一个原因是这允许项目轻松迁移到不同的数据库,特别是如果 ORM 方法与默认 ORM 不同,或者如果数据库没有用于 Django 的 ORM 包。发生这种情况时,我们只需要更新存储库中的查询,而无需触及我们 api 中的服务。这是一个例子:

                       From RDBMS
      ModelServices        |       ModelRepository
ModelRepository().find(id) | Model.objects.get(pk=id)

                        To NoSQL
      ModelServices        |       ModelRepository
ModelRepository().find(id) | Model.find_one({"_id": id})

进入全屏模式 退出全屏模式

API

api 是存储我们端点的所有类视图的地方。目前,它只有 services 文件夹,其中存储了基于模型的子文件夹,并且每个子文件夹都有专门用于每个 CRUD 操作的文件。在这个例子中,我们有一个 blogs 文件夹和一个 read blog 文件,用于查看特定的 blog 记录:

api/services/blogs/read_blog.py

from rest_framework.views import APIView
from rest_framework.response import Response

from resources.repositories.blog_repository import BlogRepository
from resources.serializers.blog_serializer import BlogSerializer

class ReadBlogService(APIView):
  def get(self, request, id, format=None):
    blog = BlogRepository().find(id)

    return Response(BlogSerializer(blog, many=False).data)

进入全屏模式 退出全屏模式

最终调整

现在,我们可以编辑 project.urls 文件来注册新的博客服务:

项目/urls.py

from django.contrib import admin
from django.urls import path

from api.services.blogs.read_blog import ReadBlogService

urlpatterns = [
    path('admin/', admin.site.urls),
    path('blog/<int:id>', ReadBlogService.as_view()),
]

进入全屏模式 退出全屏模式

结论

这是我到目前为止所概念化的。它可能看起来很复杂,但那是因为它适用于中型和大型项目。它对小型应用程序没有用处。当然,我不认为这是 Django 程序员的理想选择。正如我之前提到的,有很多方法可以构建 Django 项目。毫无疑问,还有其他更好且经过实战考验的设计。但我会尽我最大的努力使它成为一个潜在的选择。

您对此有何看法?

Logo

Python社区为您提供最前沿的新闻资讯和知识内容

更多推荐