Django:当应用程序似乎耦合时,如何完全解耦应用程序



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

我声明这个免责声明是因为很多 Django 资源似乎假设人们知道这些事情。这使得对于只是一个(次权力)用户的人来说,理解一些文档和 SO 问题变得困难。 因此,请牢记这一点来回答这个问题。

问题

这些问题的灵感来自@håkan的"何时在django中使用startapp创建新应用程序?"和@antti rasinen给出的答案,该答案链接到James Bennett的2008年PyCon演示文稿

贝内特演讲中的几个关键点是:

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

这让我想到了他的"项目耦合杀死重用"部分,其中提到:

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

问题 0

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

问题1

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

当应用共享模型时,我该怎么办?

在巴雷特的幻灯片中,他暗示用户注册和用户配置文件是不同的,应该是不同的应用程序。 (他当然指出配置文件与用户注册无关)。

因此,如果我两者都想要,我的项目会有两个应用程序吗,例如:

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

即使应用程序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)去? 我是否为每个其他应用程序制作这些文件的副本,以便即使这是多余的也可以运行它们?

哪个使我的应用更灵活?

问题 0

Python 上下文中的"模块"只是一个包含定义和语句的文件。因此,"包下的相关模块"实际上只是意味着"根据代码正在执行的操作将代码拆分为单独的文件"。

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

问题1

当应用共享模型时,我该怎么办?

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

这两个应用程序彼此有关系并没有错 - 见下文。

问题2

假设我的主应用程序(

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

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

用户模型实际上就是一个很好的例子。Django 允许你指定一个自定义用户模型,让你存储你想要的关于用户的任何额外数据。

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

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

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

在Django 生态系统中,这种可配置性的例子有数百个。例如,Django 本身附带了自己的django.contrib.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 应用程序都做一件事,而且做得很好。

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

例如:ProductCategoryColorImage

"一起改变什么,在一起">

您将有很多逻辑可以在该应用程序中仅包含这些逻辑。

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

例如:一个完全独立的可重用应用程序将是一个只需要 Django 中包含的User模型、SessionsGroups的应用程序。你会得到dependent但仍然是自主应用程序的想法。

毕竟,app是项目的一部分......无论是在这里还是在构建它之后的其他部分。把它看成是一个简单的函数......可以单独运行,也可以依赖于其他功能结果...在什么时候您将所有内容都保存在一个函数中,以及何时决定将它们分成 2 个单独的函数。 所以:

  • 问题0:

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

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

  • 问题1:

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

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

  • 问题2:

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

  • 问题3:

你可以随心所欲。

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

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

问题0:

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

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

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

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

让我们以博客为例。

代码重用:

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

项目结构:

博客项目

-常用应用

--抽象用户(抽象类(就像Java对应物一样)

--抽象活动

--摘要评论

--摘要文章

-项目应用程序

--BlogUser (扩展 AbstractUser)

--BlogActivity (扩展 AbstractActivity)

--BlogComment (扩展 AbstractComment)

--博客文章(扩展摘要文章)

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

关系解耦:

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

项目结构:

博客项目

-用户

-用户活动关系

-活动

-品

-文章评论关系

-评论

-用户评论关系

-等等

功能解耦:

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

项目结构:

博客项目

-品

-活动

-用户

-评论

我在这里想说的一点是,选择权在你。在更复杂的项目中,它不会那么白和黑。

根据"应用程序"对您意味着什么,以及您希望它在特定项目和其他项目中做什么,您可以决定特定的结构。

Django 保持抽象,以便你能够做到这一点。

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

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

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

相关内容

最新更新