如何将逻辑正确地分离到单独的应用程序中?

How to separate logic correctly into separate applications?

我实现了一个简单的 django 网站,我试图在不同的应用程序中将网站的不同部分分开,但我遇到了一些问题:

我现在有两个 Django 应用程序(核心 - 页眉、页脚、索引在哪里)和(objects - 我有 objects 我想在索引页列出的地方):

core/templates/header.html(header 元素、登录、注销等)

core/templates/index.html(html 标签、块等):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    {% block 'head-title' %}
    {% endblock %}
    {% load static %}
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <script
      src="https://code.jquery.com/jquery-3.4.1.min.js"
      integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
      crossorigin="anonymous">
    </script>
    <script src="{% static 'core/js/custom.js' %}"></script>
</head>
<body>
    {% include 'header.html' %}
    {% block 'body' %}
    {% endblock %}
</body>
</html>

core/templates/home.html(主页 - 这里我想列出所有 Object 并为它们实现过滤器):

{% extends 'index.html' %}

{% block 'body' %}
{% endblock %}

core/views.py:

from django.shortcuts import render, redirect


def show_home_page(request):
    return render(request, "home.html")

好的,一切都很完美,但现在我不知道如何添加元素列表:

我尝试的是使用 Object.objects.all()show_home_page() 函数中调用 Object 模型并将此列表传递给 home.html 并且过滤器使用参数调用相同的函数,例如 def show_home_page(request, price_up, distance): 但是后来我在 core APP 中弄乱了 objects 逻辑,我认为这不好。变体 2 是在 objects/views.py 中设置此逻辑,但我认为我应该从 objects 应用程序 return home.html 再次不正确。

有什么想法吗?

这种设计问题其他人很难回答,而且你在这里的时间比我长,我不确定我是否会帮助你...

无论如何,进行拆分的原因是您想要将 'core' 重新用于多个应用程序,每个应用程序中具有不同的对象(?)。否则,很容易在一个应用程序中实现这一切。

我有几个不同的应用程序,每个都有不同的模型。我重复使用了一个通用的页眉和页脚。我认为正确的设计实际上是构建应用程序,通过专用于这些应用程序的 url 与您想要的对象进行交互,无所不在的 'core' 函数和链接在上下文处理器中处理(context processor 是returns 渲染期间可用的上下文变量的函数。

努力使特征(和层)很好地解耦是一个值得称赞的目标,但您仍然需要让每个人在某个时候一起工作...这意味着您 确实 需要某处的一些耦合。

第一个明显的 "integration layer" 候选者是模板 - 它们(大部分)是特定于项目的(一些可重复使用的应用程序提供模板,但这些通常用作示例/起点,可以根据您的项目需求进行定制) ,并且可以使用它们(与自定义模板标签和上下文处理器一起)将来自不同应用程序的功能绑定在一起。

但有时您需要的不仅仅是模板层集成。我在大多数 django 项目上所做的是让一个 "main" 应用程序充当 "integration" 层——允许这个应用程序依赖于任何其他应用程序,但不允许任何应用程序依赖它。此应用通常会托管主页、基本模板、静态资产等。

FWIW 我通常也有一个 "core" 应用程序提供项目领域层的核心(模型,业务逻辑等),每个人都可以依赖它但不允许依赖任何其他应用程序(当然 auth 等 contrib 应用程序除外)。

请注意(正如 Atcrank 已经提到的)实际上有两种 django 应用程序:可重用应用程序和特定于项目的应用程序。一个可重用的应用程序显然必须具有尽可能少的依赖项(当然 none 对您的项目特定的应用程序 - 看起来很明显),但它还必须提供尽可能多的 "hooks" 以便与您的项目的集成特定需求(通过信号、自定义模板标签、可覆盖模板、抽象基础 类、mixins 等)。

项目特定的应用程序 OTHO 是特定于您的项目的,所以如果它依赖于另一个应用程序也可以,只要您避免循环依赖 - 因此我的三明治式 "core-apps-main" 模式,为其他人所依赖的事物和依赖于其他人的事物提供一个位置(以及其他功能之间的某个位置)。

在您的示例中,您命名的 "core" 看起来实际上想成为我自己的 "main" 图层,而您命名的 "objects" 可能是我的 "core"或一些项目特定的应用程序。

One more question.. What about if in core/views.py call objects/views.py function which return list with objects (filtered or not) and pass this list to home.html (...) Or create something like service, which operate with Objects model

这不会改变太多 wrt/ 依赖项 - 而不是依赖于 objects.models,您的核心应用程序现在依赖于 objects.views 或某些 "service"(无论它应该是什么),它本身依赖于 objects.models,因此您要用间接依赖替换直接依赖 - 这不太明显并且调试起来很痛苦(我曾经遇到过一个循环导入问题,通过它产生了十几个间接级别django 信号、"clever" 黑客攻击、动态导入等,我可以告诉你,追踪起来并不有趣)。

现在正如我所说,您将不得不以一种或另一种方式耦合您的应用程序以使它们协同工作,两个明显的地方是 1/ 模板层和 2/ 专用 "main" 应用程序(你可以随便叫它 - 我将它命名为 "main" 因为它是应用程序入口点的规范名称 - 这里的要点是允许此应用程序依赖于所有其他应用程序但不允许其他应用程序应该永远依赖它)。

如果您想使用模板作为集成层,例如 appA.views.somemodel_index 的模板可以显示来自 appB.models 的信息而 appA 对此一无所知,简单明显的解决方案是在 appB 中添加一些自定义模板标签,它将检索/格式化/呈现这些信息,并在模板中需要的地方使用此自定义模板标签。

但是您在模板层只能做这么多,一些需要了解 models/functions/whatever 来自不同的、假定不相关的应用程序的功能将在视图或模型(信号等)层中更好地实现,因此使用 "integration" 应用程序。