【问题标题】:Don't understand Django's ORM - Models不了解 Django 的 ORM - 模型
【发布时间】:2020-04-18 05:30:12
【问题描述】:

由于这些天我有一些空闲时间,我决定学习一门新语言会很好。所以我选择了 python,因为它很受欢迎,而且我对 Django 很感兴趣。

几个小时后,尽管所有与语法相关的困难都源于一种新语言,但我还是设法进行了简单的后端逻辑设计(我的“应用程序”应该做什么)。现在下一步是将我的代码介绍给 Django,以最终以某种方式使该逻辑“真实”,并在此过程中学习一些 HTML、CSS。

在学习了 Django 的官方教程后,我觉得我学到了足够的东西来开始我的项目。

在我开始谈论 Django 的 ORM 之前,我想说的是,根据我在教程中看到和学到的内容,我非常喜欢 Django 的所有与 Web 相关的实用程序(视图、路径、模板)。至少目前看来,它们真的很容易学习和使用。

现在关于 ORM。

首先,我觉得有必要澄清一下,这是我这辈子使用的第二个ORM;我在其中一门课程中使用的第一个是 Java 的 JPA。

根据我使用 JPA 所学到的知识,我觉得 ORM 的主要目标之一是尽量不让我修改我已经编写的所有代码。这样一来,应用程序的开发就会很容易:

  1. st - 设计后端代码(案例用途、应用模型:类、对象、函数)。
  2. nd - 将该模型映射到关系模型,以便可以将其保存在数据库中。
  3. rd - 创建视图和所有前端的东西。

我遇到 Django 的 ORM 的第一个问题是没有 OneToMany 关系,所以如果在我的起始代码中我有:

    class Question:
       pass

    class Exam:
        __init__(self, questions):
            self.questions = questions     # list of questions

我不得不把它改成:

    class Question:
       exam = models.ForeignKey('Exam', on_delete=models.CASACADE, related_name='questions', ...)

    class Exam:
       pass

也许我不是很了解 Django 的“模型”,毕竟我只是一个新手。但我觉得这很可怕。如果我的“考试”类有依赖于使用这样的问题列表来完成工作的方法怎么办。我已经看到我可以使用an_exam.questions.all() 访问它,但我觉得这很糟糕,因为例如:

  1. 至少我的 IDE (PyCharm) 无法识别这些属性;我猜它们是在运行时定义的。这可能会导致运行时错误,以防我的类中使用了许多这些属性并且我弄乱了它们的名称。

  2. 再加上这样一个事实,即我可以在单独的文件中拥有我的课程(考试)和定义 ForeignKey(问题)的课程。所以我不能轻易知道我的班级有什么属性(更多错误)。

  3. 最后,我猜an_exam.questions.all() 返回与给定考试相关的所有问题,这些问题保存在数据库中。那些还没有的呢?

我遇到的另一个问题是我不应该重写__init__ 方法。这将使我改变我的类初始化的所有事件。当然,我可以绕过它,正如我在互联网上的某个地方看到的那样,定义一个 class_method 以便an_exam = Exam.new_exam();但为什么 Django 会让我这样做呢?

合并这两个问题:如果要初始化的类需要一个通过 OneToMany 关系与之相关的元素列表呢?以“考试”为例,我不仅会求助于创建初始化方法的阴暗想法,而且我还必须创建几个额外的设置方法,这些方法利用自动生成的“问题”属性(以及其他属性,如果存在)正确设置属性:

class Question:
    exam = models.ForeignKey('Exam', on_delete=models.CASACADE, related_name='questions', ...)

class Exam:
    @classmethod
    def new_exam(cls, questions):
        exam = Exam()
        exam.set_questions(questions)
        return exam

    def set_questions(questions):
        for q in questions:
            q.exam = self
            q.save()
            # something like this

最后我想说我知道我是 Django 和 python 本身的新手。这就是为什么我确定我所说的一切以及更多内容一定是错误的;我这样做的目的是有人会指出我的错误。

我觉得我误解了 Django 模型的真正含义。我没有多想它们,我认为它们指的是我实际的应用程序逻辑/后端设计模型:职责是如何分配的,要满足的要求以及背后的逻辑。

我期待有人能照亮我走出这种压倒性和令人失望的感觉的道路。感谢您阅读到最后:)

【问题讨论】:

  • 关于 PyCharm 没有拾取模型之间自动生成的反向关系的第一个问题。这是专业版中提供的东西,但社区版中没有
  • 这很酷。但是,我仍然觉得在我的代码中使用它们并围绕它们重构我的代码有点错误。
  • 但是反过来呢?如果您在模型上定义了“一对多”字段,那么您将在相关模型上隐式创建外键
  • Django 的设计理念是大多数数据输入都是通过用户输入完成的。您创建 Exam 类的实例并将 question 关系的成员传递给它的示例具有 Django 范例 - docs.djangoproject.com/en/3.0/topics/forms/modelforms/…
  • 如果您来自 Java,最好不要过多回顾 Java 中的工作方式,而是使用 Python,这一定会让您感到沮丧。例如,getter 和 setter 是另一个巨大的分歧点,以及私有和公共属性限定符。话虽如此,欢迎来到????!

标签: python django


【解决方案1】:

以下是我对模型/ORM 的看法以及它们为何如此令人愉悦的原因:没有它们,创建和维护 SQL(查询)和 DDL(创建/更新数据库表)需要大量工作。使用 ORM,您可以省去所有这些工作:它们定义数据库表(每个表都作为模型)并将 PK、FK 关系转换为对象关系。示例比抽象描述要好,所以这是我的一个应用程序中一个非常简单的模型的示例:

class LimitType(models.Model):
    limit = models.CharField(max_length=25, unique=True, blank=False)
    description = models.CharField(max_length=50, unique=False, blank=True)
    departments = models.ManyToManyField(Department, blank=True, related_name='departmental_limits')
    createTimestamp = models.DateTimeField(auto_now_add=True)
    updateTimestamp = models.DateTimeField(auto_now=True)
    createdById = models.ForeignKey(Users, on_delete=models.PROTECT, unique=False, null=False)
    modifiedById = models.ForeignKey(Users, on_delete=models.PROTECT, unique=False, null=False)

    def __str__(self):
        return self.limit

    class Meta:
        ordering = ["limit"]

注意这个类是一个模型类,而不是一些通用类。模型应该代表数据库中的内容——它们的“工作”是将关系数据库表封装为对象。还要注意这里的思维模式,此 LimitType 类中的每个字段都与(可交换/可插入)数据库中的列直接相关(如果没有 ORM 层或类似的等价物,这是不可行的壮举)。

通过实例化模型,可以使用 python 的所有语法约定来收集、选择、更新和排序相关对象:

For type in LimitType.objects.all():
  type.do_something() 

此外,很容易遍历 OneToMany(和 ManyToMany)关系:

for type in LimitType.objects.all():
    print(type.departments.count())

这些 sn-ps 是可以在其他类或 Django 项目的视图中找到的类型代码。

当然,这只是冰山一角; Django 和 SQLAlchemy 的 ORM 中有很多方便的功能,值得两者学习。也许您的困惑/沮丧源于将模型类与其他类型的类混为一谈。将它们分开(将它们放在 models.py 文件中)并将它们视为 (1) 您的持久性手段和 (2) 应用程序结构关系的蓝图。

【讨论】:

  • 是的!我想我的困惑就在那里。所以你说我应该尽量不去思考 Java 教给我的纯 OOP。我应该设计我的“模型类”,主要目的是保存我的数据,并从那里改进它们以实现我需要完成的功能;使用函数方法甚至其他“类”。我认为首先做我的基本平面模型类是个好主意,然后在其他任何事情之后开始考虑应用程序的视图,看看我真正需要涵盖的逻辑是什么,最后添加该逻辑。我明白了吗?
  • 是的,听起来您现在已经掌握了。详细说明:首先定义数据库中的数据,然后通过添加函数(和属性!)来完善模型。一个超级简单的例子,可能是一个名为 full_name 的方法,它返回两个连接在一起的字段:self.first_name + ' ' + self.last_name
猜你喜欢
  • 1970-01-01
  • 2015-01-14
  • 1970-01-01
  • 1970-01-01
  • 2016-06-20
  • 2017-11-25
  • 1970-01-01
  • 2013-05-16
  • 1970-01-01
相关资源
最近更新 更多