【问题标题】:Django: how to fully decouple apps when it seems they are coupled? [closed]Django:当它们看起来耦合时,如何完全解耦应用程序? [关闭]
【发布时间】:2018-02-16 17:17:26
【问题描述】:

注意:我不是一个正统 python 程序员...但我广泛使用 python。我会做一些事情,比如编写带有继承的类、使用迭代器和理解等。我的观点是我对语言没有完整的掌握,例如什么确切构成了一个python对象,为什么除了指定一个模块之外还需要__init__.py等等。关于Django,我已经编写了多应用程序站点(在S.O.的帮助下)并且有真的很喜欢 Django 的模板系统、块以及它们是如何嵌套的。现在我的应用程序完全解耦和可重用了吗?这是这篇文章的主题。

我声明这个免责声明是因为很多 Django 资源似乎都假设人们知道这些事情。这有助于理解一些文档和 S.O.对于一个只是(次级)用户的人来说,问题很困难。因此,请记住这一点来回答这个问题。

问题

这些问题的灵感来自@håkan 的问题When to create a new app with startapp in django?@antti rasinen 给出的answer,链接到James Bennett 2008 年的PyCon presentation

Bennett 演讲的几个关键点是:

  1. 网站是应用的集合
  2. 一个应用做一件事,做好一件事

这将我引向他的“项目耦合扼杀重用”部分,其中提到:

  • 直接在 Python 路径上的单个模块(注册、标记等)
  • 包下的相关模块(ellington.events、ellington.podcasts 等)

问题 0

在这种情况下,“模块”只是由其他应用组成的应用?

问题 1

(具有相关功能和共享模型的应用程序)

应用共享模型时应该怎么做?

在 Barrett 的幻灯片中,他暗示用户注册和用户配置文件是不同的,应该是不同的应用程序。 (他当然表示个人资料与用户注册无关)。

所以如果我想要两者,我的项目是否会有两个应用程序,例如:

  • 用户注册
  • 用户配置文件

即使应用程序user-profile 需要来自user-registration 的用户模型?还是我做一个应用(module):

  • 用户应用
    • 注册
    • 个人资料

两者都包含?

问题 2

(具有不同功能但共享模型的应用程序)

扩展问题 1 中的示例,假设我的主应用(或主应用使用的其他应用)利用了用户模型的某些方面(例如,如果它是聊天网站,则为最近活跃的成员)。

显然,我的主应用程序从用户模型中获取了这些信息。我的主应用现在是否捆绑在 user-app 模块下?

这可能不是最好的例子,但要点如下:

我有两个应用程序app-dependencyapp-needs-dependency,每个应用程序都做它的一件事和一件事……只是app-needs-dependency 需要来自app-dependency 的信息。在这种情况下我该怎么办,如果关于app-needs-dependency 的其他所有内容都 与app-dependency 完全解耦(因此它可以用于其他项目)?

问题 3

(为灵活性编写应用程序)

现在我的网站上有几个应用程序。每个应用程序都只做一件事并且做得很好。在这种情况下,主应用程序用作登录页面/概览。

我希望我的所有其他应用使用/继承主应用的静态和模板文件。

我在哪里存储所有静态文件和模板?在主应用程序中并将其设置为其他应用程序的默认设置?或者这些静态文件/模板(例如base.cssbase.html)应该去哪里? 我是否为每个其他应用制作了这些文件的副本,以便即使这是多余的也可以运行它们?

哪一点让我的应用更灵活?

【问题讨论】:

    标签: python django


    【解决方案1】:

    问题 0

    Python 上下文中的“模块”只是一个包含定义和语句的文件。所以“一个包下的相关模块”实际上只是意味着“根据代码的作用将代码拆分成单独的文件”。

    将其描述为“由其他应用组成的应用”是为了开始混淆 Django 的应用概念和 Python 的模块概念(如上所述,模块只是一个包含一些代码的文件)。

    问题 1

    应用共享模型时应该怎么做?

    您仍应尝试坚持“应用程序只做一件事并做好”的格言。在这种情况下,单独的个人资料和注册应用程序似乎是个好主意 - 因为它们具有完全不同的功能。注册应用程序将包含允许用户在您的网站上注册的逻辑。个人资料应用就是关于您将存储有关用户的哪些信息。

    这两个应用相互关联并没有错 - 见下文。

    问题 2

    假设我的主应用(或主应用使用的其他应用)利用了用户模型的某些方面(例如,如果它是聊天网站,则为最近活跃的成员)。显然,我的主应用程序从用户模型中获取了这些信息。我的主应用现在是否捆绑在用户应用下?

    没有。它仍然应该是一个单独的应用程序,并带有指向另一个应用程序的链接。

    用户模型实际上就是一个很好的例子。 Django 允许您指定一个custom user model,它可以让您存储您想要的有关用户的任何其他数据。

    现在,有大量第三方应用程序可以为用户执行注册、身份验证等操作。它们旨在与任何用户模型一起使用,而不仅仅是 Django 的默认模型。他们这样做的方式是在需要引用User 模型的任何地方使用get_user_model(),而不是直接导入django.contrib.auth.models.User

    这意味着您可以将这些第三方应用程序与您为自己的项目定义的任何用户模型一起使用。

    Django 的get_user_model() 实用程序用于服务一个非常常见的用例。然而,同样的原则可以扩展到您自己的应用程序。如果您认为应该可交换的应用之间存在依赖关系,那么您可以提供一种将其交换出去的方法 - 例如,允许使用您的应用的任何其他项目指定替代方案的设置/配置。

    在 Django 生态系统中有数百个这种可配置性的示例。例如,Django 本身带有自己的django.contrib.auth 身份验证应用程序。但是,如果您想实现自己的身份验证逻辑,则不必自己重新实现整个身份验证应用程序(这将是一个巨大的痛苦)。相反,您指定一个authentication backend,它的身份验证应用程序将使用它来进行身份验证。 auth 应用旨在允许任何项目以最小的努力换出其核心功能。

    因此,在您的 main 应用程序中,您可以定义一个设置来控制要使用的 profile 模型。这意味着如果其他人想要使用不同的配置文件模型,他们只需更改此设置即可。它们不再与您的 profile 应用绑定。

    例如 - 假设您有一个 main 应用程序,该应用程序具有一个显示一些用户数据的视图,但还提供了一个指向由不同应用程序提供的注册视图的链接。无论他们使用什么注册应用程序,您都希望其他人能够使用该应用程序。所以你可以像这样使这个视图可重复使用:

    main/views.py:

    from django.contrib.auth import get_user_model
    from django.conf import settings
    from django.urls import reverse
    
    class UserDetailView(DetailView):
    
        # First of all, we're using get_user_model so that a project
        # can specify whatever user model it wants, and still use this
        # view.
        model = get_user_model()
    
        def get_context_data(self, *args, *kwargs):
            ctx = super().get_context_data(*args, **kwargs)
            # We want to add a link to a registration view into this template context.
            # But we want this to be configurable.
            # Your REGISTRATION_URL would be something like 'profile:registration'
            ctx['registration_link'] = reverse(settings.REGISTRATION_URL)
            return ctx
    

    问题 3

    在这种情况下,主应用程序充当着陆页/概览。我希望我的所有其他应用程序使用/继承主应用程序的静态和模板文件。我在哪里存储所有静态文件和模板?

    您应该将模板存储在每个相应的应用程序中。如果您的主应用程序提供基本模板,那么这些模板应该驻留在主应用程序中。

    如果您的个人资料应用提供了注册视图,那么该模板应该存在于个人资料应用中。从主应用程序扩展基本模板没有任何问题 - 这很容易被想要的项目覆盖。

    可以对两个应用之间的关联做出假设 - 只要您小心允许覆盖这些假设。

    【讨论】:

    • 非常感谢您在回答这个问题时花费的时间和精力。我确信我缺乏 Django 应用程序的设置/配置功能(例如如何定义默认模型/默认模板)的知识,这使得这很难。我也明白为什么用户注册和用户配置文件应该分开,但不明白为什么它们不应该被封装在一个更强大的用户应用程序下——(我仍然不清楚)。如果可能的话,如果您能举一个小例子来说明如何执行上述用户操作,我将不胜感激。它不需要花里胡哨,只是一个大纲,所以我知道如何为其他应用程序这样做。
    • 我添加了一个有些人为的例子来尝试说明这个概念。
    • 关于问题1(应用共享模型):假设一个场景(Large Project Scenario),当项目变大时,应用之间共享的模型很多(外键)。 Django 迁移会产生如此多的依赖关系,django 迁移会变得混乱和错误吗?我的意思是,我知道一个应用程序与另一个应用程序相关是可以的。但是如果有很多应用程序和更多应用程序即将推出怎么办?
    【解决方案2】:

    我不得不承认您的问题不是技术问题,而是概念性和教条性问题。 没有一个答案是绝对的和普遍有效的,关于你项目的结构和行为方式的每一个细节都可以改变观点。 正如您所写,每个 Django 应用程序都做一件事并且做得很好。

    我会将这一点扩展到每个应用程序不应包含超过一个 Model 并且最多是壁橱依赖项。

    例如:ProductCategoryColorImage

    “一起改变什么,保持在一起”

    只有这些逻辑,您将在该应用程序中涵盖大量逻辑。

    尝试将 Django 框架视为创建项目的工具..这是最终目标...但是如果您还想创建可重用的应用程序,请尝试尽可能独立地创建它们,或者至少依赖于某些Django 功能:

    ex:一个可重用的应用程序和完全独立的应用程序只需要在 Django 中包含User Model、SessionsGroups。你明白dependent 的想法,但仍然是自主应用。

    app 毕竟是项目的一部分......无论是在这里还是在您构建它之后的其他部分。把它看成一个简单的函数……可以单独运行,也可以依赖于其他函数结果……什么时候你把所有东西都放在一个函数里,什么时候你决定把它们分成两个单独的函数。 所以:

    • 问题 0:

    应用程序是可以由它自己运行的最小部分...具有模型、视图、模板、url、静态文件。

    它也可以依赖于其他应用程序...所以答案是肯定的

    • 问题 1:

    始终按功能将事物分开... 用户身份验证处理用户创建及其身份验证

    用户个人资料处理用户的个人数据

    • 问题 2:

    没有任何东西被捆绑。一切都与 2 个不同但相互依赖的应用保持在同一级别

    • 问题 3:

    你可以随心所欲。

    您可以将静态作为中心位置和特定于每个应用程序或所有中心位置的模板。 这里没有正确答案,只有适合您的项目的答案。

    【讨论】:

    • 对不起,我不听你的回答。是的,这个问题更具概念性(但如果您知道如何实现它,请随意链接 git repo 演示)。如果一个应用程序依赖于一个模型,我如何编写它来接受这个模型(如果我在另一个项目中使用它)?那么对于 Q1,我为什么不将两个独立的功能放在一个用户应用程序下呢?对于 Q3,在任何地方复制粘贴相同的文件是没有意义的,特别是如果它是像 css 这样的自定义静态文件,因为它的扩展性很差。老实说,我目前认为您的答案不足以回答这个问题
    【解决方案3】:

    这是一个很好的问题,它涵盖了我在开始使用 Django 时问自己的与构建项目相关的所有问题。

    问题 0:

    是的,在这种情况下,模块是由多个应用程序(ellington.events、ellington.podcasts)组成的应用程序。

    问题 1、问题 2、问题 3:

    Django 是一个通用的全栈 Web 框架。由于它是通用的,因此很大程度上取决于您的特定用例。 您不需要让整个 Django 项目遵循特定的结构(如果您想实现代码重用、功能解耦和关系解耦)。

    话虽如此,如果您可以优先考虑您想要实现的目标,您可以选择一种模式而不是另一种模式。

    我们以博客为例。

    代码重用:

    为了实现最大程度的代码重用,您必须确定项目的哪些部分值得重用。完成后,您可以相应地设置项目结构。

    项目结构:

    博客项目

    -CommonApps

    --AbstractUser(抽象类(就像它的java对应))

    --抽象活动

    --摘要评论

    --摘要文章

    -项目应用

    --BlogUser(扩展AbstractUser)

    --BlogActivity(扩展AbstractActivity)

    --BlogComment(扩展AbstractComment)

    --BlogArticle(扩展AbstractArticle)

    可以跨多个项目共享的功能应该在抽象应用程序中实现,特定于项目的功能可以在项目应用程序中实现。

    关系解耦:

    您可以创建应用来表示其他两个应用之间的关系,并实现涉及该关系中两个不同应用的所有功能。

    项目结构:

    博客项目

    -用户

    -用户活动关系

    -活动

    -文章

    -ArticleCommentRelation

    -评论

    -用户评论关系

    -等等

    功能解耦:

    这是最常见的做法 - 为特定功能创建应用程序。

    项目结构:

    博客项目

    -文章

    -活动

    -用户

    -评论

    我在这里要强调的是,选择权在你。在更复杂的项目中,它不会那么白和黑。

    您可以根据“应用”对您的意义以及您希望它在特定项目和其他项目中执行的操作来决定特定的结构。

    Django 将其保持抽象以使您能够做到这一点。

    我总是选择对特定项目有意义的应用设置。在一个项目中,并非所有应用程序都是可重用的。在所有情况下,拥有灵活/可重用的应用程序并不有意义。

    作为一般的经验法则,Django 开发人员说 App 应该是可以用一句话描述其功能的东西。但是 Django 的设计是为了让您可以在必要时为您的项目改变规则。

    免责声明:功能解耦和关系解耦不是教科书术语。我只是用它们来描述我在这里的意思。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-02
      • 2012-05-21
      • 2016-09-09
      • 2015-11-22
      相关资源
      最近更新 更多