Django 新手在模型和可重用业务逻辑方面困难重重

2 投票
2 回答
1117 浏览
提问于 2025-04-18 12:13

我是一名 .net 开发者,之前一直在使用 asp.net mvc 框架,现在想尝试进入 Python 的世界,特别是想用 Django 编写一些网站,但我对 Django 的结构感到很困惑。

在 asp.net mvc 中,我把 asp.net mvc 框架当作一个展示层,我的业务逻辑和数据层是独立的。这是我所有 asp.net mvc 网站的基本结构:

enter image description here

这个网站是一个 asp.net mvc 项目,而业务逻辑和数据类型的项目是类库(dll 文件)。在业务逻辑项目中,我使用一个实体框架模型(它生成的所有类),并创建一些我称之为“管理器”的类,这些类包含系统的核心逻辑。例如,如果这个网站是一个博客网站,“UsersMgr” 会包含“注册用户、获取用户、确认用户账户”等操作,而“PostsMgr” 会包含“添加帖子、删除帖子、编辑帖子、给帖子添加评论”等操作。

这种方法的想法是,网站只是一个展示层,它使用业务逻辑,但并不是紧密耦合在一起。我通常会添加一个“管理员控制台”(另一个 asp.net mvc 网站给管理员使用)、一些合作伙伴的“报告”(比如想象一下这个博客有广告,我们给合作伙伴一个登录,让他们可以更新广告并查看广告展示次数的报告等)、一个“REST API”,这样如果我想创建一个移动应用,就可以通过 REST API 暴露业务逻辑,还有定时任务来运行维护任务或每天结束时发送报告到我的邮箱等。

在我之前的 .net 项目中,添加这些新东西的方式是这样的:

enter image description here

基本上,所有这些新添加的项目都是业务逻辑的“消费者”。

我很难理解如何在 Django 中实现类似的功能,因为 web 应用似乎与它们的模型紧密耦合,而这些模型是数据库表的映射。那么如果我想在一个非 Django 网站中重用业务逻辑,我应该把它放在哪里呢?

关于 Django 应用,我到处都看到说把网站拆分成 Django 应用是个好主意,但当概念通常是耦合在一起的时候,应该怎么做呢?例如,一个博客可能有用户、帖子、评论、标签等。我的问题是,这一切都是相互关联的,帖子属于某个用户,标签和评论与帖子相关联。你会怎么处理这些关系呢?

如果有人能帮我解决这个问题,我会非常感激。我为我的树莓派写了一些 Python 脚本,觉得这个语言真不错,但我在 Django 上遇到了困难。肯定有我遗漏的东西……

谢谢!

2 个回答

3

我看到很多开发者对Django有相同的疑问。其实,Django对MVC的理解有点不同。Django的ORM(对象关系映射)把和数据库的连接给抽象化了,让模型来处理业务逻辑。虽然Django允许你自己管理数据库结构,使用触发器、进程等等,但Django也能在应用层面上完成这些事情,这样你的项目就完全不依赖于具体的数据库了。

Django还提倡使用“胖模型”和管理器。Django中的管理器在某种程度上可以替代MVC中的控制器,因为它们的工作是处理模型实例的集合。不过,你可以扩展模型管理器,以适应你习惯的指令。

数据库独立性对某些人来说是个很大的好处,但这也意味着你的数据模型是和Django项目绑定在一起的,可能在其他项目中用处不大。不过,嘿,这就是接口的用处所在!

Django内置了一个管理应用,定制起来非常简单,可以根据你的需求进行调整。

说到接口,Django的视图就是这样的一个接口。它并不告诉你应该如何展示数据。Django有一个非常强大的模板框架,但这其实是可选的。如果你想实现一个REST接口,Django REST FrameworkDjango Tastypie可以在几个小时内搞定,因为你的业务逻辑已经用一种通用的语言定义好了,这些应用都能很好地利用这些逻辑并美观地展示出来。

接下来谈谈应用的部分。可以把你的项目想象成一些功能模块:用户、注册、博客、评论、标签管理。用户可以有用户、个人资料和组模型,注册不需要模型,博客有帖子和分类模型,标签管理则处理标签模型。

应用就是一些打包好的功能,它们有模型、视图、网址等等,能够一起工作是没问题的。你可以在应用之间建立关系(比如博客帖子有很多标签)。当然,如果你删除了标签应用,博客可能会出问题,所以要提前考虑这些事情(也许是标签有很多博客帖子)。

如果你还有其他问题,可以在评论里问我,我会尽量解释得清楚一些。

3

视图和模型

模型就像是你数据类型的部分,而视图则是网站的界面,通常会包含你“管理者”需要的代码。

我猜“业务逻辑”指的是一些规则,比如“只有符合特定条件的用户才能评论帖子”。你说把这些逻辑直接放在视图里不太好是对的,因为如果用户通过其他方式(比如本地运行的命令行工具)访问系统,那么你就得在那儿重复这些逻辑。

解决办法是把业务逻辑加到模型里,通过在模型类中添加自定义函数,这些函数相当于你管理者的“GetX”、“GetY”,并在模型的保存钩子中加入“这个用户能否做这个”的逻辑。

你完全可以在视图和模型之间创建一个管理层,比如:

models.py:

class Post(models.Model):
    ...

class Comment(models.Model):
    user = models.ForeignKey(User)
    post = models.ForeignKey(Post)
    text = models.CharField(...)

managers.py:

class PostManager(object):
    @staticmethod
    def getPost(id):
        return Post.object.get(pk=id)

    @staticmethod
    def addComment(post, comment_text, user):
        comment = Comment(post=post, user=user, text=comment_text)
        # check stuff
        comment.save()
    ...

views.py:

def add_comment(request, post_id):
    ...
    PostManager.addComment(post=PostManager.getPost(post_id),
                           user=request.user,
                           request.POST['text'])
    ...

不过这样做有几个缺点:

  • 模型实例的API仍然可以绕过这些检查
  • 你会失去模型API的表达能力
  • 代码会显得有点冗长

主要的好处是,你可以轻松地把整个Django模型替换成其他的ORM(对象关系映射)。但如果你不太可能这样做,那就不建议走这条路。

Django应用

把东西分成不同的应用是个好主意。应用应该根据功能进行划分,分开你整个项目中不同的部分。

在你的例子中(博客、帖子、评论、用户),其实你有两个应用。一个是处理用户的(登录/登出、注册、密码重置等),另一个是处理博客的(发帖、评论等)。

博客应用依赖于用户应用并不是坏事,利用用户应用提供的现有功能在博客应用中是合理的。

从长远来看,这样做可以方便重用(你可能还有其他项目需要用户功能,但不需要博客功能)。

撰写回答